Skip to content

Commit 6f7704e

Browse files
authored
Properly handle typeof this.xxx in isTypeParameterPossiblyReferenced (#54208)
1 parent 1ea21e1 commit 6f7704e

File tree

4 files changed

+71
-19
lines changed

4 files changed

+71
-19
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18837,25 +18837,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1883718837
case SyntaxKind.TypeQuery:
1883818838
const entityName = (node as TypeQueryNode).exprName;
1883918839
const firstIdentifier = getFirstIdentifier(entityName);
18840-
const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier);
18841-
const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called
18842-
let tpScope: Node;
18843-
if (tpDeclaration.kind === SyntaxKind.TypeParameter) { // Type parameter is a regular type parameter, e.g. foo<T>
18844-
tpScope = tpDeclaration.parent;
18845-
}
18846-
else if (tp.isThisType) {
18847-
// Type parameter is the this type, and its declaration is the class declaration.
18848-
tpScope = tpDeclaration;
18849-
}
18850-
else {
18851-
// Type parameter's declaration was unrecognized.
18852-
// This could happen if the type parameter comes from e.g. a JSDoc annotation, so we default to returning true.
18853-
return true;
18854-
}
18855-
18856-
if (firstIdentifierSymbol.declarations) {
18857-
return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) ||
18858-
some((node as TypeQueryNode).typeArguments, containsReference);
18840+
if (!isThisIdentifier(firstIdentifier)) { // Don't attempt to analyze typeof this.xxx
18841+
const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier);
18842+
const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called
18843+
const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent : // Type parameter is a regular type parameter, e.g. foo<T>
18844+
tp.isThisType ? tpDeclaration : // Type parameter is the this type, and its declaration is the class declaration.
18845+
undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation.
18846+
if (firstIdentifierSymbol.declarations && tpScope) {
18847+
return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) ||
18848+
some((node as TypeQueryNode).typeArguments, containsReference);
18849+
}
1885918850
}
1886018851
return true;
1886118852
case SyntaxKind.MethodDeclaration:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/typeofThisInMethodSignature.ts ===
2+
// Repro from #54167
3+
4+
export class A {
5+
>A : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))
6+
7+
x = 1
8+
>x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))
9+
10+
a(x: typeof this.x): void {}
11+
>a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))
12+
>x : Symbol(x, Decl(typeofThisInMethodSignature.ts, 4, 3))
13+
>this.x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))
14+
>this : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))
15+
>x : Symbol(A.x, Decl(typeofThisInMethodSignature.ts, 2, 16))
16+
}
17+
18+
const a = new A().a(1);
19+
>a : Symbol(a, Decl(typeofThisInMethodSignature.ts, 7, 5))
20+
>new A().a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))
21+
>A : Symbol(A, Decl(typeofThisInMethodSignature.ts, 0, 0))
22+
>a : Symbol(A.a, Decl(typeofThisInMethodSignature.ts, 3, 6))
23+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/typeofThisInMethodSignature.ts ===
2+
// Repro from #54167
3+
4+
export class A {
5+
>A : A
6+
7+
x = 1
8+
>x : number
9+
>1 : 1
10+
11+
a(x: typeof this.x): void {}
12+
>a : (x: typeof this.x) => void
13+
>x : number
14+
>this.x : number
15+
>this : this
16+
>x : number
17+
}
18+
19+
const a = new A().a(1);
20+
>a : void
21+
>new A().a(1) : void
22+
>new A().a : (x: number) => void
23+
>new A() : A
24+
>A : typeof A
25+
>a : (x: number) => void
26+
>1 : 1
27+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Repro from #54167
5+
6+
export class A {
7+
x = 1
8+
a(x: typeof this.x): void {}
9+
}
10+
11+
const a = new A().a(1);

0 commit comments

Comments
 (0)