diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f1813882898c..3cd54756236a5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14313,6 +14313,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + if (isInJSFile(declaration)) { + const thisTag = getJSDocThisTag(declaration); + if (thisTag && thisTag.typeExpression) { + thisParameter = createSymbolWithType(createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), getTypeFromTypeNode(thisTag.typeExpression)); + } + } + const classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClassOrInterface(getMergedSymbol((declaration.parent as ClassDeclaration).symbol)) : undefined; diff --git a/tests/baselines/reference/constructorTagWithThisTag.symbols b/tests/baselines/reference/constructorTagWithThisTag.symbols index 309e9514a5617..30db64e9d504c 100644 --- a/tests/baselines/reference/constructorTagWithThisTag.symbols +++ b/tests/baselines/reference/constructorTagWithThisTag.symbols @@ -9,10 +9,10 @@ function C() { this.e = this.m + 1 >this.e : Symbol(e, Decl(classthisboth.js, 2, 11)) ->this : Symbol(__type, Decl(classthisboth.js, 2, 10)) +>this : Symbol(this) >e : Symbol(C.e, Decl(classthisboth.js, 5, 14)) >this.m : Symbol(m, Decl(classthisboth.js, 2, 22)) ->this : Symbol(__type, Decl(classthisboth.js, 2, 10)) +>this : Symbol(this) >m : Symbol(m, Decl(classthisboth.js, 2, 22)) } diff --git a/tests/baselines/reference/inferThis.symbols b/tests/baselines/reference/inferThis.symbols new file mode 100644 index 0000000000000..58bfad0accf01 --- /dev/null +++ b/tests/baselines/reference/inferThis.symbols @@ -0,0 +1,51 @@ +=== /a.js === +export class C { +>C : Symbol(C, Decl(a.js, 0, 0)) + + /** + * @template T + * @this {T} + * @return {T} + */ + static a() { +>a : Symbol(C.a, Decl(a.js, 0, 16)) + + return this; +>this : Symbol(this) + } + + /** + * @template T + * @this {T} + * @return {T} + */ + b() { +>b : Symbol(C.b, Decl(a.js, 8, 5)) + + return this; +>this : Symbol(this) + } +} + +const a = C.a(); +>a : Symbol(a, Decl(a.js, 20, 5)) +>C.a : Symbol(C.a, Decl(a.js, 0, 16)) +>C : Symbol(C, Decl(a.js, 0, 0)) +>a : Symbol(C.a, Decl(a.js, 0, 16)) + +a; // typeof C +>a : Symbol(a, Decl(a.js, 20, 5)) + +const c = new C(); +>c : Symbol(c, Decl(a.js, 23, 5)) +>C : Symbol(C, Decl(a.js, 0, 0)) + +const b = c.b(); +>b : Symbol(b, Decl(a.js, 24, 5)) +>c.b : Symbol(C.b, Decl(a.js, 8, 5)) +>c : Symbol(c, Decl(a.js, 23, 5)) +>b : Symbol(C.b, Decl(a.js, 8, 5)) + +b; // C +>b : Symbol(b, Decl(a.js, 24, 5)) + diff --git a/tests/baselines/reference/inferThis.types b/tests/baselines/reference/inferThis.types new file mode 100644 index 0000000000000..cfb81de24aa55 --- /dev/null +++ b/tests/baselines/reference/inferThis.types @@ -0,0 +1,54 @@ +=== /a.js === +export class C { +>C : C + + /** + * @template T + * @this {T} + * @return {T} + */ + static a() { +>a : (this: T) => T + + return this; +>this : T + } + + /** + * @template T + * @this {T} + * @return {T} + */ + b() { +>b : (this: T) => T + + return this; +>this : T + } +} + +const a = C.a(); +>a : typeof C +>C.a() : typeof C +>C.a : (this: T) => T +>C : typeof C +>a : (this: T) => T + +a; // typeof C +>a : typeof C + +const c = new C(); +>c : C +>new C() : C +>C : typeof C + +const b = c.b(); +>b : C +>c.b() : C +>c.b : (this: T) => T +>c : C +>b : (this: T) => T + +b; // C +>b : C + diff --git a/tests/baselines/reference/thisTag1.symbols b/tests/baselines/reference/thisTag1.symbols index 473a80be70f57..04ef577f7dfd6 100644 --- a/tests/baselines/reference/thisTag1.symbols +++ b/tests/baselines/reference/thisTag1.symbols @@ -9,7 +9,7 @@ function f(s) { return this.n + s.length >this.n : Symbol(n, Decl(a.js, 0, 12)) ->this : Symbol(__type, Decl(a.js, 0, 11)) +>this : Symbol(this) >n : Symbol(n, Decl(a.js, 0, 12)) >s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(a.js, 4, 11)) diff --git a/tests/cases/conformance/jsdoc/inferThis.ts b/tests/cases/conformance/jsdoc/inferThis.ts new file mode 100644 index 0000000000000..09204fc72b6ae --- /dev/null +++ b/tests/cases/conformance/jsdoc/inferThis.ts @@ -0,0 +1,31 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @filename: /a.js + +export class C { + /** + * @template T + * @this {T} + * @return {T} + */ + static a() { + return this; + } + + /** + * @template T + * @this {T} + * @return {T} + */ + b() { + return this; + } +} + +const a = C.a(); +a; // typeof C + +const c = new C(); +const b = c.b(); +b; // C