diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b1d258e6c2afd..62aab9ca5c062 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7307,7 +7307,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signature.thisParameter) { return symbolToParameterDeclaration(signature.thisParameter, context); } - if (signature.declaration) { + if (signature.declaration && isInJSFile(signature.declaration)) { const thisTag = getJSDocThisTag(signature.declaration); if (thisTag && thisTag.typeExpression) { return factory.createParameterDeclaration( diff --git a/tests/baselines/reference/quickInfoJsDocThisTag.baseline b/tests/baselines/reference/quickInfoJsDocThisTag.baseline new file mode 100644 index 0000000000000..a873e110a4d3e --- /dev/null +++ b/tests/baselines/reference/quickInfoJsDocThisTag.baseline @@ -0,0 +1,68 @@ +=== /a.ts === +// /** @this {number} */ +// function f() { +// ^ +// | ---------------------------------------------------------------------- +// | function f(): void +// | @this +// | ---------------------------------------------------------------------- +// this +// } + +[ + { + "marker": { + "fileName": "/a.ts", + "position": 32, + "name": "" + }, + "item": { + "kind": "function", + "kindModifiers": "", + "textSpan": { + "start": 31, + "length": 1 + }, + "displayParts": [ + { + "text": "function", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "f", + "kind": "functionName" + }, + { + "text": "(", + "kind": "punctuation" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "void", + "kind": "keyword" + } + ], + "documentation": [], + "tags": [ + { + "name": "this" + } + ] + } + } +] \ No newline at end of file diff --git a/tests/baselines/reference/thisInFunctionCall.types b/tests/baselines/reference/thisInFunctionCall.types index 4b5455d4d15f9..fc7b0b748f41d 100644 --- a/tests/baselines/reference/thisInFunctionCall.types +++ b/tests/baselines/reference/thisInFunctionCall.types @@ -84,7 +84,7 @@ class Test { /** @this {Test} */ function (d) { ->function (d) { console.log(d === this.data.length) } : (this: Test, d: number) => void +>function (d) { console.log(d === this.data.length) } : (d: number) => void >d : number console.log(d === this.data.length) @@ -117,7 +117,7 @@ class Test { /** @this {Test} */ function (d) { ->function (d) { return d === this.data.length } : (this: Test, d: number) => boolean +>function (d) { return d === this.data.length } : (d: number) => boolean >d : number return d === this.data.length diff --git a/tests/baselines/reference/thisInFunctionCallJs.errors.txt b/tests/baselines/reference/thisInFunctionCallJs.errors.txt new file mode 100644 index 0000000000000..d752c5ddc4d37 --- /dev/null +++ b/tests/baselines/reference/thisInFunctionCallJs.errors.txt @@ -0,0 +1,46 @@ +/a.js(9,26): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +/a.js(15,31): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. + + +==== /a.js (2 errors) ==== + class Test { + constructor() { + /** @type {number[]} */ + this.data = [1, 2, 3]; + } + + finderRaw() { + this.data.find(function (d) { + return d === this.data.length + ~~~~ +!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +!!! related TS2738 /a.js:8:24: An outer value of 'this' is shadowed by this container. + }) + } + + forEacherRaw() { + this.data.forEach(function (d) { + console.log(d === this.data.length) + ~~~~ +!!! error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +!!! related TS2738 /a.js:14:27: An outer value of 'this' is shadowed by this container. + }) + } + + forEacher() { + this.data.forEach( + /** @this {Test} */ + function (d) { + console.log(d === this.data.length) + }, this) + } + + finder() { + this.data.find( + /** @this {Test} */ + function (d) { + return d === this.data.length + }, this) + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/thisInFunctionCallJs.symbols b/tests/baselines/reference/thisInFunctionCallJs.symbols new file mode 100644 index 0000000000000..b1f3d30c99401 --- /dev/null +++ b/tests/baselines/reference/thisInFunctionCallJs.symbols @@ -0,0 +1,105 @@ +=== /a.js === +class Test { +>Test : Symbol(Test, Decl(a.js, 0, 0)) + + constructor() { + /** @type {number[]} */ + this.data = [1, 2, 3]; +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(Test, Decl(a.js, 0, 0)) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) + } + + finderRaw() { +>finderRaw : Symbol(Test.finderRaw, Decl(a.js, 4, 5)) + + this.data.find(function (d) { +>this.data.find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(Test, Decl(a.js, 0, 0)) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>d : Symbol(d, Decl(a.js, 7, 33)) + + return d === this.data.length +>d : Symbol(d, Decl(a.js, 7, 33)) + + }) + } + + forEacherRaw() { +>forEacherRaw : Symbol(Test.forEacherRaw, Decl(a.js, 10, 5)) + + this.data.forEach(function (d) { +>this.data.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(Test, Decl(a.js, 0, 0)) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) +>d : Symbol(d, Decl(a.js, 13, 36)) + + console.log(d === this.data.length) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>d : Symbol(d, Decl(a.js, 13, 36)) + + }) + } + + forEacher() { +>forEacher : Symbol(Test.forEacher, Decl(a.js, 16, 5)) + + this.data.forEach( +>this.data.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(Test, Decl(a.js, 0, 0)) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) + + /** @this {Test} */ + function (d) { +>d : Symbol(d, Decl(a.js, 21, 18)) + + console.log(d === this.data.length) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>d : Symbol(d, Decl(a.js, 21, 18)) +>this.data.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(this) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + }, this) +>this : Symbol(Test, Decl(a.js, 0, 0)) + } + + finder() { +>finder : Symbol(Test.finder, Decl(a.js, 24, 5)) + + this.data.find( +>this.data.find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(Test, Decl(a.js, 0, 0)) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) + + /** @this {Test} */ + function (d) { +>d : Symbol(d, Decl(a.js, 29, 18)) + + return d === this.data.length +>d : Symbol(d, Decl(a.js, 29, 18)) +>this.data.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>this.data : Symbol(Test.data, Decl(a.js, 1, 19)) +>this : Symbol(this) +>data : Symbol(Test.data, Decl(a.js, 1, 19)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + }, this) +>this : Symbol(Test, Decl(a.js, 0, 0)) + } +} + diff --git a/tests/baselines/reference/thisInFunctionCallJs.types b/tests/baselines/reference/thisInFunctionCallJs.types new file mode 100644 index 0000000000000..c0a131679af65 --- /dev/null +++ b/tests/baselines/reference/thisInFunctionCallJs.types @@ -0,0 +1,134 @@ +=== /a.js === +class Test { +>Test : Test + + constructor() { + /** @type {number[]} */ + this.data = [1, 2, 3]; +>this.data = [1, 2, 3] : number[] +>this.data : number[] +>this : this +>data : number[] +>[1, 2, 3] : number[] +>1 : 1 +>2 : 2 +>3 : 3 + } + + finderRaw() { +>finderRaw : () => void + + this.data.find(function (d) { +>this.data.find(function (d) { return d === this.data.length }) : number +>this.data.find : { (predicate: (value: number, index: number, obj: number[]) => value is S, thisArg?: any): S; (predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any): number; } +>this.data : number[] +>this : this +>data : number[] +>find : { (predicate: (value: number, index: number, obj: number[]) => value is S, thisArg?: any): S; (predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any): number; } +>function (d) { return d === this.data.length } : (d: number) => boolean +>d : number + + return d === this.data.length +>d === this.data.length : boolean +>d : number +>this.data.length : any +>this.data : any +>this : any +>data : any +>length : any + + }) + } + + forEacherRaw() { +>forEacherRaw : () => void + + this.data.forEach(function (d) { +>this.data.forEach(function (d) { console.log(d === this.data.length) }) : void +>this.data.forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void +>this.data : number[] +>this : this +>data : number[] +>forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void +>function (d) { console.log(d === this.data.length) } : (d: number) => void +>d : number + + console.log(d === this.data.length) +>console.log(d === this.data.length) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>d === this.data.length : boolean +>d : number +>this.data.length : any +>this.data : any +>this : any +>data : any +>length : any + + }) + } + + forEacher() { +>forEacher : () => void + + this.data.forEach( +>this.data.forEach( /** @this {Test} */ function (d) { console.log(d === this.data.length) }, this) : void +>this.data.forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void +>this.data : number[] +>this : this +>data : number[] +>forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void + + /** @this {Test} */ + function (d) { +>function (d) { console.log(d === this.data.length) } : (this: Test, d: number) => void +>d : number + + console.log(d === this.data.length) +>console.log(d === this.data.length) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>d === this.data.length : boolean +>d : number +>this.data.length : number +>this.data : number[] +>this : Test +>data : number[] +>length : number + + }, this) +>this : this + } + + finder() { +>finder : () => void + + this.data.find( +>this.data.find( /** @this {Test} */ function (d) { return d === this.data.length }, this) : number +>this.data.find : { (predicate: (value: number, index: number, obj: number[]) => value is S, thisArg?: any): S; (predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any): number; } +>this.data : number[] +>this : this +>data : number[] +>find : { (predicate: (value: number, index: number, obj: number[]) => value is S, thisArg?: any): S; (predicate: (value: number, index: number, obj: number[]) => unknown, thisArg?: any): number; } + + /** @this {Test} */ + function (d) { +>function (d) { return d === this.data.length } : (this: Test, d: number) => boolean +>d : number + + return d === this.data.length +>d === this.data.length : boolean +>d : number +>this.data.length : number +>this.data : number[] +>this : Test +>data : number[] +>length : number + + }, this) +>this : this + } +} + diff --git a/tests/cases/compiler/thisInFunctionCallJs.ts b/tests/cases/compiler/thisInFunctionCallJs.ts new file mode 100644 index 0000000000000..9d2a2fdd53a75 --- /dev/null +++ b/tests/cases/compiler/thisInFunctionCallJs.ts @@ -0,0 +1,41 @@ +// @target: es2015 +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @noImplicitThis: true +// @filename: /a.js + +class Test { + constructor() { + /** @type {number[]} */ + this.data = [1, 2, 3]; + } + + finderRaw() { + this.data.find(function (d) { + return d === this.data.length + }) + } + + forEacherRaw() { + this.data.forEach(function (d) { + console.log(d === this.data.length) + }) + } + + forEacher() { + this.data.forEach( + /** @this {Test} */ + function (d) { + console.log(d === this.data.length) + }, this) + } + + finder() { + this.data.find( + /** @this {Test} */ + function (d) { + return d === this.data.length + }, this) + } +} diff --git a/tests/cases/fourslash/quickInfoJsDocThisTag.ts b/tests/cases/fourslash/quickInfoJsDocThisTag.ts new file mode 100644 index 0000000000000..decce84b2f19d --- /dev/null +++ b/tests/cases/fourslash/quickInfoJsDocThisTag.ts @@ -0,0 +1,9 @@ +/// +// @strict: true +// @filename: /a.ts +/////** @this {number} */ +////function f/**/() { +//// this +////} + +verify.baselineQuickInfo();