Skip to content

Commit

Permalink
🤖 Pick PR #54208 (Properly handle typeof this.xxx i...) into releas…
Browse files Browse the repository at this point in the history
…e-5.1 (#54413)

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
  • Loading branch information
TypeScript Bot and ahejlsberg authored May 29, 2023
1 parent 42e7839 commit 898edb5
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 19 deletions.
29 changes: 10 additions & 19 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18813,25 +18813,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.TypeQuery:
const entityName = (node as TypeQueryNode).exprName;
const firstIdentifier = getFirstIdentifier(entityName);
const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier);
const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called
let tpScope: Node;
if (tpDeclaration.kind === SyntaxKind.TypeParameter) { // Type parameter is a regular type parameter, e.g. foo<T>
tpScope = tpDeclaration.parent;
}
else if (tp.isThisType) {
// Type parameter is the this type, and its declaration is the class declaration.
tpScope = tpDeclaration;
}
else {
// Type parameter's declaration was unrecognized.
// This could happen if the type parameter comes from e.g. a JSDoc annotation, so we default to returning true.
return true;
}

if (firstIdentifierSymbol.declarations) {
return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) ||
some((node as TypeQueryNode).typeArguments, containsReference);
if (!isThisIdentifier(firstIdentifier)) { // Don't attempt to analyze typeof this.xxx
const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier);
const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called
const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent : // Type parameter is a regular type parameter, e.g. foo<T>
tp.isThisType ? tpDeclaration : // Type parameter is the this type, and its declaration is the class declaration.
undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation.
if (firstIdentifierSymbol.declarations && tpScope) {
return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) ||
some((node as TypeQueryNode).typeArguments, containsReference);
}
}
return true;
case SyntaxKind.MethodDeclaration:
Expand Down
23 changes: 23 additions & 0 deletions tests/baselines/reference/typeofThisInMethodSignature.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
=== tests/cases/compiler/typeofThisInMethodSignature.ts ===
// Repro from #54167

export class A {
>A : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))

x = 1
>x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))

a(x: typeof this.x): void {}
>a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))
>x : Symbol(x, Decl(typeofThisInMethodSignature.ts, 4, 3))
>this.x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))
>this : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))
>x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))
}

const a = new A().a(1);
>a : Symbol(a, Decl(typeofThisInMethodSignature.ts, 7, 5))
>new A().a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))
>A : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))
>a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))

27 changes: 27 additions & 0 deletions tests/baselines/reference/typeofThisInMethodSignature.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
=== tests/cases/compiler/typeofThisInMethodSignature.ts ===
// Repro from #54167

export class A {
>A : A

x = 1
>x : number
>1 : 1

a(x: typeof this.x): void {}
>a : (x: typeof this.x) => void
>x : number
>this.x : number
>this : this
>x : number
}

const a = new A().a(1);
>a : void
>new A().a(1) : void
>new A().a : (x: number) => void
>new A() : A
>A : typeof A
>a : (x: number) => void
>1 : 1

11 changes: 11 additions & 0 deletions tests/cases/compiler/typeofThisInMethodSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @strict: true
// @noEmit: true

// Repro from #54167

export class A {
x = 1
a(x: typeof this.x): void {}
}

const a = new A().a(1);

0 comments on commit 898edb5

Please sign in to comment.