diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8e24fee20606d..d87fcefe79faf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31689,12 +31689,15 @@ namespace ts { return false; } const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node : - isVariableDeclaration(node) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : + (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : undefined; if (func) { - // If the node has a @class tag, treat it like a constructor. + // If the node has a @class or @constructor tag, treat it like a constructor. if (getJSDocClassTag(node)) return true; + // If the node is a property of an object literal. + if (isPropertyAssignment(walkUpParenthesizedExpressions(func.parent))) return false; + // If the symbol of the node has members, treat it like a constructor. const symbol = getSymbolOfNode(func); return !!symbol?.members?.size; diff --git a/tests/baselines/reference/functionExpressionNames.symbols b/tests/baselines/reference/functionExpressionNames.symbols index 1675f159134b3..ca1d8479ae57e 100644 --- a/tests/baselines/reference/functionExpressionNames.symbols +++ b/tests/baselines/reference/functionExpressionNames.symbols @@ -22,8 +22,7 @@ var o = { >C : Symbol(C, Decl(b.js, 5, 9)) this.c = 'nested object' ->this.c : Symbol(C.c, Decl(b.js, 6, 20)) ->this : Symbol(C, Decl(b.js, 6, 6)) +>this : Symbol(o, Decl(b.js, 5, 7)) >c : Symbol(C.c, Decl(b.js, 6, 20)) } } diff --git a/tests/baselines/reference/functionExpressionNames.types b/tests/baselines/reference/functionExpressionNames.types index 50c45ed46d30d..d803666bbb943 100644 --- a/tests/baselines/reference/functionExpressionNames.types +++ b/tests/baselines/reference/functionExpressionNames.types @@ -31,7 +31,7 @@ var o = { this.c = 'nested object' >this.c = 'nested object' : "nested object" >this.c : any ->this : this +>this : { C: typeof C; } >c : any >'nested object' : "nested object" } diff --git a/tests/baselines/reference/objectPropertyAsClass.symbols b/tests/baselines/reference/objectPropertyAsClass.symbols new file mode 100644 index 0000000000000..ad9712fa52395 --- /dev/null +++ b/tests/baselines/reference/objectPropertyAsClass.symbols @@ -0,0 +1,52 @@ +=== tests/cases/compiler/index.js === +const a1 = { +>a1 : Symbol(a1, Decl(index.js, 0, 5)) + + foo() { +>foo : Symbol(foo, Decl(index.js, 0, 12)) + + this.x = 0; +>this : Symbol(a1, Decl(index.js, 0, 10)) +>x : Symbol(x, Decl(index.js, 1, 11)) + } +} + +const a2 = { +>a2 : Symbol(a2, Decl(index.js, 6, 5)) + + foo: function() { +>foo : Symbol(foo, Decl(index.js, 6, 12)) + + this.x = 0; +>this : Symbol(a2, Decl(index.js, 6, 10)) +>x : Symbol(foo.x, Decl(index.js, 7, 21)) + } +} + +const b1 = { +>b1 : Symbol(b1, Decl(index.js, 12, 5)) + + /** @class */ + foo() { +>foo : Symbol(foo, Decl(index.js, 12, 12)) + + this.x = 0; +>this : Symbol(b1, Decl(index.js, 12, 10)) +>x : Symbol(x, Decl(index.js, 14, 11)) + } +} + +const b2 = { +>b2 : Symbol(b2, Decl(index.js, 19, 5)) + + /** @class */ + foo: function() { +>foo : Symbol(foo, Decl(index.js, 19, 12)) + + this.x = 0; +>this.x : Symbol(foo.x, Decl(index.js, 21, 21)) +>this : Symbol(foo, Decl(index.js, 21, 8)) +>x : Symbol(foo.x, Decl(index.js, 21, 21)) + } +} + diff --git a/tests/baselines/reference/objectPropertyAsClass.types b/tests/baselines/reference/objectPropertyAsClass.types new file mode 100644 index 0000000000000..7d27103e0118a --- /dev/null +++ b/tests/baselines/reference/objectPropertyAsClass.types @@ -0,0 +1,69 @@ +=== tests/cases/compiler/index.js === +const a1 = { +>a1 : { foo(): void; } +>{ foo() { this.x = 0; }} : { foo(): void; } + + foo() { +>foo : () => void + + this.x = 0; +>this.x = 0 : 0 +>this.x : any +>this : { foo(): void; } +>x : any +>0 : 0 + } +} + +const a2 = { +>a2 : { foo: typeof foo; } +>{ foo: function() { this.x = 0; }} : { foo: typeof foo; } + + foo: function() { +>foo : typeof foo +>function() { this.x = 0; } : typeof foo + + this.x = 0; +>this.x = 0 : 0 +>this.x : any +>this : { foo: typeof foo; } +>x : any +>0 : 0 + } +} + +const b1 = { +>b1 : { foo(): void; } +>{ /** @class */ foo() { this.x = 0; }} : { foo(): void; } + + /** @class */ + foo() { +>foo : () => void + + this.x = 0; +>this.x = 0 : 0 +>this.x : any +>this : { foo(): void; } +>x : any +>0 : 0 + } +} + +const b2 = { +>b2 : { foo: typeof foo; } +>{ /** @class */ foo: function() { this.x = 0; }} : { foo: typeof foo; } + + /** @class */ + foo: function() { +>foo : typeof foo +>function() { this.x = 0; } : typeof foo + + this.x = 0; +>this.x = 0 : 0 +>this.x : any +>this : this +>x : any +>0 : 0 + } +} + diff --git a/tests/baselines/reference/thisInObjectJs.js b/tests/baselines/reference/thisInObjectJs.js new file mode 100644 index 0000000000000..e70e3c8eb6c46 --- /dev/null +++ b/tests/baselines/reference/thisInObjectJs.js @@ -0,0 +1,39 @@ +//// [index.js] +export { } +let obj = { + x: 10, + y: [1], + fun: function() { + this.x = 1 + this/*1*/ + }, + f2: function() { + this.x + this/*2*/ + }, + f3: (function() { + this.x = 1 + this/*3*/ + }), +} + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var obj = { + x: 10, + y: [1], + fun: function () { + this.x = 1; + this; /*1*/ + }, + f2: function () { + this.x; + this; /*2*/ + }, + f3: (function () { + this.x = 1; + this; /*3*/ + }) +}; diff --git a/tests/baselines/reference/thisInObjectJs.symbols b/tests/baselines/reference/thisInObjectJs.symbols new file mode 100644 index 0000000000000..f0ed418f6a691 --- /dev/null +++ b/tests/baselines/reference/thisInObjectJs.symbols @@ -0,0 +1,45 @@ +=== tests/cases/compiler/index.js === +export { } +let obj = { +>obj : Symbol(obj, Decl(index.js, 1, 3)) + + x: 10, +>x : Symbol(x, Decl(index.js, 1, 11)) + + y: [1], +>y : Symbol(y, Decl(index.js, 2, 8)) + + fun: function() { +>fun : Symbol(fun, Decl(index.js, 3, 9)) + + this.x = 1 +>this.x : Symbol(x, Decl(index.js, 1, 11)) +>this : Symbol(obj, Decl(index.js, 1, 9)) +>x : Symbol(fun.x, Decl(index.js, 4, 19)) + + this/*1*/ +>this : Symbol(obj, Decl(index.js, 1, 9)) + + }, + f2: function() { +>f2 : Symbol(f2, Decl(index.js, 7, 4)) + + this.x +>this.x : Symbol(x, Decl(index.js, 1, 11)) +>this : Symbol(obj, Decl(index.js, 1, 9)) +>x : Symbol(x, Decl(index.js, 1, 11)) + + this/*2*/ +>this : Symbol(obj, Decl(index.js, 1, 9)) + + }, + f3: (function() { +>f3 : Symbol(f3, Decl(index.js, 11, 4)) + + this.x = 1 +>x : Symbol((Anonymous function).x, Decl(index.js, 12, 19)) + + this/*3*/ + }), +} + diff --git a/tests/baselines/reference/thisInObjectJs.types b/tests/baselines/reference/thisInObjectJs.types new file mode 100644 index 0000000000000..3752241f53715 --- /dev/null +++ b/tests/baselines/reference/thisInObjectJs.types @@ -0,0 +1,61 @@ +=== tests/cases/compiler/index.js === +export { } +let obj = { +>obj : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } +>{ x: 10, y: [1], fun: function() { this.x = 1 this/*1*/ }, f2: function() { this.x this/*2*/ }, f3: (function() { this.x = 1 this/*3*/ }),} : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } + + x: 10, +>x : number +>10 : 10 + + y: [1], +>y : number[] +>[1] : number[] +>1 : 1 + + fun: function() { +>fun : typeof fun +>function() { this.x = 1 this/*1*/ } : typeof fun + + this.x = 1 +>this.x = 1 : 1 +>this.x : number +>this : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } +>x : number +>1 : 1 + + this/*1*/ +>this : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } + + }, + f2: function() { +>f2 : () => void +>function() { this.x this/*2*/ } : () => void + + this.x +>this.x : number +>this : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } +>x : number + + this/*2*/ +>this : { x: number; y: number[]; fun: typeof fun; f2: () => void; f3: typeof (Anonymous function); } + + }, + f3: (function() { +>f3 : typeof (Anonymous function) +>(function() { this.x = 1 this/*3*/ }) : typeof (Anonymous function) +>function() { this.x = 1 this/*3*/ } : typeof (Anonymous function) + + this.x = 1 +>this.x = 1 : 1 +>this.x : any +>this : any +>x : any +>1 : 1 + + this/*3*/ +>this : any + + }), +} + diff --git a/tests/cases/compiler/objectPropertyAsClass.ts b/tests/cases/compiler/objectPropertyAsClass.ts new file mode 100644 index 0000000000000..a4b32acfaae44 --- /dev/null +++ b/tests/cases/compiler/objectPropertyAsClass.ts @@ -0,0 +1,30 @@ +// @allowJs: true +// @noEmit: true +// @checkJs: true + +// @filename: index.js +const a1 = { + foo() { + this.x = 0; + } +} + +const a2 = { + foo: function() { + this.x = 0; + } +} + +const b1 = { + /** @class */ + foo() { + this.x = 0; + } +} + +const b2 = { + /** @class */ + foo: function() { + this.x = 0; + } +} diff --git a/tests/cases/compiler/thisInObjectJs.ts b/tests/cases/compiler/thisInObjectJs.ts new file mode 100644 index 0000000000000..631b1b631d1b4 --- /dev/null +++ b/tests/cases/compiler/thisInObjectJs.ts @@ -0,0 +1,21 @@ +// @allowJs: true +// @outDir: out + +// @filename: index.js +export { } +let obj = { + x: 10, + y: [1], + fun: function() { + this.x = 1 + this/*1*/ + }, + f2: function() { + this.x + this/*2*/ + }, + f3: (function() { + this.x = 1 + this/*3*/ + }), +}