Don't treat object properties as potential JS contructors without JSDoc class tag (#49735)

This commit is contained in:
Jake Bailey 2022-08-10 14:19:19 -04:00 committed by GitHub
parent 382f0c3af3
commit 5fbf3b04dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 324 additions and 5 deletions

View File

@ -31906,12 +31906,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;

View File

@ -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))
}
}

View File

@ -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"
}

View File

@ -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))
}
}

View File

@ -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
}
}

View File

@ -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*/
})
};

View File

@ -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*/
}),
}

View File

@ -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
}),
}

View File

@ -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;
}
}

View File

@ -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*/
}),
}