fix(51868): this within function typed as any when annotated with JSDoc (#54516)

This commit is contained in:
Oleksandr T 2023-06-27 01:00:10 +03:00 committed by GitHub
parent 38575dc015
commit df40c7ae88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 246 additions and 10 deletions

View File

@ -28473,20 +28473,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
function getTypeForThisExpressionFromJSDoc(node: Node) {
const jsdocType = getJSDocType(node);
if (jsdocType && jsdocType.kind === SyntaxKind.JSDocFunctionType) {
const jsDocFunctionType = jsdocType as JSDocFunctionType;
if (jsDocFunctionType.parameters.length > 0 &&
jsDocFunctionType.parameters[0].name &&
(jsDocFunctionType.parameters[0].name as Identifier).escapedText === InternalSymbolName.This) {
return getTypeFromTypeNode(jsDocFunctionType.parameters[0].type!);
}
}
function getTypeForThisExpressionFromJSDoc(node: SignatureDeclaration) {
const thisTag = getJSDocThisTag(node);
if (thisTag && thisTag.typeExpression) {
return getTypeFromTypeNode(thisTag.typeExpression);
}
const signature = getSignatureOfTypeTag(node);
if (signature) {
return getThisTypeOfSignature(signature);
}
}
function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean {

View File

@ -0,0 +1,58 @@
/a.js(3,10): error TS2339: Property 'test' does not exist on type 'Foo'.
/a.js(8,10): error TS2339: Property 'test' does not exist on type 'Foo'.
/a.js(13,10): error TS2339: Property 'test' does not exist on type 'Foo'.
/a.js(18,10): error TS2339: Property 'test' does not exist on type 'Foo'.
/a.js(23,10): error TS2339: Property 'test' does not exist on type 'Foo'.
/a.js(28,10): error TS2339: Property 'test' does not exist on type 'Foo'.
==== /types.d.ts (0 errors) ====
export interface Foo {
foo: () => void;
}
export type M = (this: Foo) => void;
==== /a.js (6 errors) ====
/** @type {import('./types').M} */
export const f1 = function() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}
/** @type {import('./types').M} */
export function f2() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}
/** @type {(this: import('./types').Foo) => void} */
export const f3 = function() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}
/** @type {(this: import('./types').Foo) => void} */
export function f4() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}
/** @type {function(this: import('./types').Foo): void} */
export const f5 = function() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}
/** @type {function(this: import('./types').Foo): void} */
export function f6() {
this.test();
~~~~
!!! error TS2339: Property 'test' does not exist on type 'Foo'.
}

View File

@ -0,0 +1,62 @@
=== /types.d.ts ===
export interface Foo {
>Foo : Symbol(Foo, Decl(types.d.ts, 0, 0))
foo: () => void;
>foo : Symbol(Foo.foo, Decl(types.d.ts, 0, 22))
}
export type M = (this: Foo) => void;
>M : Symbol(M, Decl(types.d.ts, 2, 1))
>this : Symbol(this, Decl(types.d.ts, 4, 17))
>Foo : Symbol(Foo, Decl(types.d.ts, 0, 0))
=== /a.js ===
/** @type {import('./types').M} */
export const f1 = function() {
>f1 : Symbol(f1, Decl(a.js, 1, 12))
this.test();
>this : Symbol(this, Decl(types.d.ts, 4, 17))
}
/** @type {import('./types').M} */
export function f2() {
>f2 : Symbol(f2, Decl(a.js, 3, 1))
this.test();
>this : Symbol(Foo, Decl(types.d.ts, 0, 0))
}
/** @type {(this: import('./types').Foo) => void} */
export const f3 = function() {
>f3 : Symbol(f3, Decl(a.js, 11, 12))
this.test();
>this : Symbol(this, Decl(a.js, 10, 12))
}
/** @type {(this: import('./types').Foo) => void} */
export function f4() {
>f4 : Symbol(f4, Decl(a.js, 13, 1))
this.test();
>this : Symbol(Foo, Decl(types.d.ts, 0, 0))
}
/** @type {function(this: import('./types').Foo): void} */
export const f5 = function() {
>f5 : Symbol(f5, Decl(a.js, 21, 12))
this.test();
>this : Symbol(this, Decl(a.js, 20, 20))
}
/** @type {function(this: import('./types').Foo): void} */
export function f6() {
>f6 : Symbol(f6, Decl(a.js, 23, 1))
this.test();
>this : Symbol(Foo, Decl(types.d.ts, 0, 0))
}

View File

@ -0,0 +1,80 @@
=== /types.d.ts ===
export interface Foo {
foo: () => void;
>foo : () => void
}
export type M = (this: Foo) => void;
>M : (this: Foo) => void
>this : Foo
=== /a.js ===
/** @type {import('./types').M} */
export const f1 = function() {
>f1 : import("/types").M
>function() { this.test();} : (this: import("/types").Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}
/** @type {import('./types').M} */
export function f2() {
>f2 : (this: import("/types").Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}
/** @type {(this: import('./types').Foo) => void} */
export const f3 = function() {
>f3 : (this: import("/types").Foo) => void
>function() { this.test();} : (this: import("/types").Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}
/** @type {(this: import('./types').Foo) => void} */
export function f4() {
>f4 : (this: import('./types').Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}
/** @type {function(this: import('./types').Foo): void} */
export const f5 = function() {
>f5 : (this: import("/types").Foo) => void
>function() { this.test();} : (this: import("/types").Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}
/** @type {function(this: import('./types').Foo): void} */
export function f6() {
>f6 : (this: import('./types').Foo) => void
this.test();
>this.test() : any
>this.test : any
>this : import("/types").Foo
>test : any
}

View File

@ -0,0 +1,41 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @filename: /types.d.ts
export interface Foo {
foo: () => void;
}
export type M = (this: Foo) => void;
// @filename: /a.js
/** @type {import('./types').M} */
export const f1 = function() {
this.test();
}
/** @type {import('./types').M} */
export function f2() {
this.test();
}
/** @type {(this: import('./types').Foo) => void} */
export const f3 = function() {
this.test();
}
/** @type {(this: import('./types').Foo) => void} */
export function f4() {
this.test();
}
/** @type {function(this: import('./types').Foo): void} */
export const f5 = function() {
this.test();
}
/** @type {function(this: import('./types').Foo): void} */
export function f6() {
this.test();
}