Skip to content

Commit 57ebd99

Browse files
authored
Exclude typeof this from check in isConstantReference (#52680)
1 parent 1c822c4 commit 57ebd99

File tree

4 files changed

+204
-4
lines changed

4 files changed

+204
-4
lines changed

src/compiler/checker.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -26091,10 +26091,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2609126091

2609226092
function isConstantReference(node: Node): boolean {
2609326093
switch (node.kind) {
26094-
case SyntaxKind.Identifier: {
26095-
const symbol = getResolvedSymbol(node as Identifier);
26096-
return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol);
26097-
}
26094+
case SyntaxKind.Identifier:
26095+
if (!isThisInTypeQuery(node)) {
26096+
const symbol = getResolvedSymbol(node as Identifier);
26097+
return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol);
26098+
}
26099+
break;
2609826100
case SyntaxKind.PropertyAccessExpression:
2609926101
case SyntaxKind.ElementAccessExpression:
2610026102
// The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
=== tests/cases/compiler/thisInTypeQuery.ts ===
2+
// Repros from #52672
3+
4+
function assert(condition: unknown): asserts condition {
5+
>assert : Symbol(assert, Decl(thisInTypeQuery.ts, 0, 0))
6+
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
7+
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
8+
9+
if (!condition) {
10+
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
11+
12+
throw new Error();
13+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
14+
}
15+
}
16+
17+
class MyClass {
18+
>MyClass : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
19+
20+
private map = {
21+
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
22+
23+
my_key: 'example_value'
24+
>my_key : Symbol(my_key, Decl(thisInTypeQuery.ts, 9, 19))
25+
26+
};
27+
28+
runTypeFails() {
29+
>runTypeFails : Symbol(MyClass.runTypeFails, Decl(thisInTypeQuery.ts, 11, 6))
30+
31+
const params = null as any as { a: { key: string } } | null;
32+
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
33+
>a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
34+
>key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
35+
36+
assert(params);
37+
>assert : Symbol(assert, Decl(thisInTypeQuery.ts, 0, 0))
38+
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
39+
40+
type Key = keyof typeof this.map;
41+
>Key : Symbol(Key, Decl(thisInTypeQuery.ts, 15, 23))
42+
>this.map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
43+
>this : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
44+
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
45+
46+
this.map[params.a.key as Key];
47+
>this.map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
48+
>this : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
49+
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
50+
>params.a.key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
51+
>params.a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
52+
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
53+
>a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
54+
>key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
55+
>Key : Symbol(Key, Decl(thisInTypeQuery.ts, 15, 23))
56+
}
57+
}
58+
59+
class C {
60+
>C : Symbol(C, Decl(thisInTypeQuery.ts, 19, 1))
61+
62+
foo() {
63+
>foo : Symbol(C.foo, Decl(thisInTypeQuery.ts, 21, 9))
64+
65+
const x = !!true;
66+
>x : Symbol(x, Decl(thisInTypeQuery.ts, 23, 9))
67+
68+
if (x) {
69+
>x : Symbol(x, Decl(thisInTypeQuery.ts, 23, 9))
70+
71+
type T0 = typeof this;
72+
>T0 : Symbol(T0, Decl(thisInTypeQuery.ts, 24, 12))
73+
>this : Symbol(C, Decl(thisInTypeQuery.ts, 19, 1))
74+
}
75+
}
76+
}
77+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
=== tests/cases/compiler/thisInTypeQuery.ts ===
2+
// Repros from #52672
3+
4+
function assert(condition: unknown): asserts condition {
5+
>assert : (condition: unknown) => asserts condition
6+
>condition : unknown
7+
8+
if (!condition) {
9+
>!condition : boolean
10+
>condition : unknown
11+
12+
throw new Error();
13+
>new Error() : Error
14+
>Error : ErrorConstructor
15+
}
16+
}
17+
18+
class MyClass {
19+
>MyClass : MyClass
20+
21+
private map = {
22+
>map : { my_key: string; }
23+
>{ my_key: 'example_value' } : { my_key: string; }
24+
25+
my_key: 'example_value'
26+
>my_key : string
27+
>'example_value' : "example_value"
28+
29+
};
30+
31+
runTypeFails() {
32+
>runTypeFails : () => void
33+
34+
const params = null as any as { a: { key: string } } | null;
35+
>params : { a: { key: string;}; } | null
36+
>null as any as { a: { key: string } } | null : { a: { key: string;}; } | null
37+
>null as any : any
38+
>null : null
39+
>a : { key: string; }
40+
>key : string
41+
>null : null
42+
43+
assert(params);
44+
>assert(params) : void
45+
>assert : (condition: unknown) => asserts condition
46+
>params : { a: { key: string; }; } | null
47+
48+
type Key = keyof typeof this.map;
49+
>Key : "my_key"
50+
>this.map : { my_key: string; }
51+
>this : this
52+
>map : { my_key: string; }
53+
54+
this.map[params.a.key as Key];
55+
>this.map[params.a.key as Key] : string
56+
>this.map : { my_key: string; }
57+
>this : this
58+
>map : { my_key: string; }
59+
>params.a.key as Key : "my_key"
60+
>params.a.key : string
61+
>params.a : { key: string; }
62+
>params : { a: { key: string; }; }
63+
>a : { key: string; }
64+
>key : string
65+
}
66+
}
67+
68+
class C {
69+
>C : C
70+
71+
foo() {
72+
>foo : () => void
73+
74+
const x = !!true;
75+
>x : true
76+
>!!true : true
77+
>!true : false
78+
>true : true
79+
80+
if (x) {
81+
>x : true
82+
83+
type T0 = typeof this;
84+
>T0 : this
85+
>this : this
86+
}
87+
}
88+
}
89+
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Repros from #52672
5+
6+
function assert(condition: unknown): asserts condition {
7+
if (!condition) {
8+
throw new Error();
9+
}
10+
}
11+
12+
class MyClass {
13+
private map = {
14+
my_key: 'example_value'
15+
};
16+
17+
runTypeFails() {
18+
const params = null as any as { a: { key: string } } | null;
19+
assert(params);
20+
type Key = keyof typeof this.map;
21+
this.map[params.a.key as Key];
22+
}
23+
}
24+
25+
class C {
26+
foo() {
27+
const x = !!true;
28+
if (x) {
29+
type T0 = typeof this;
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)