Skip to content

Commit cf23b47

Browse files
committed
reorder comprisions and handle flow cache key
1 parent 58a3693 commit cf23b47

6 files changed

+339
-13
lines changed

src/compiler/checker.ts

+8-11
Original file line numberDiff line numberDiff line change
@@ -26474,10 +26474,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2647426474
const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer);
2647526475
return key && key + "." + propName;
2647626476
}
26477-
else if (isElementAccessExpression(node) && isIdentifier(node.argumentExpression) && isConstantReference(node.argumentExpression)) {
26478-
const propertySymbol = getResolvedSymbol(node.argumentExpression);
26477+
else if (isElementAccessExpression(node) && isConstantReference(node.argumentExpression)) {
26478+
const propertyCacheKey = getFlowCacheKey(node.argumentExpression, unknownType, unknownType, flowContainer);
26479+
if (!propertyCacheKey) {
26480+
return undefined;
26481+
}
2647926482
const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer);
26480-
return key && key + "." + getSymbolId(propertySymbol);
26483+
return key && key + "[" + propertyCacheKey + "]";
2648126484
}
2648226485
break;
2648326486
case SyntaxKind.ObjectBindingPattern:
@@ -26529,14 +26532,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2652926532
isMatchingReference((source as AccessExpression).expression, (target as AccessExpression).expression);
2653026533
}
2653126534
else {
26532-
if (
26533-
isElementAccessExpression(source) && isElementAccessExpression(target)
26534-
&& isConstantReference(source.argumentExpression) && isConstantReference(target.argumentExpression)
26535-
) {
26536-
return isMatchingReference(source.expression, target.expression) &&
26537-
isMatchingReference(source.argumentExpression, target.argumentExpression);
26538-
}
26539-
return false;
26535+
return isElementAccessExpression(source) && isElementAccessExpression(target) && isMatchingReference(source.expression, target.expression) &&
26536+
isMatchingReference(source.argumentExpression, target.argumentExpression) && isConstantReference(source.argumentExpression) && isConstantReference(target.argumentExpression);
2654026537
}
2654126538
case SyntaxKind.QualifiedName:
2654226539
return isAccessExpression(target) &&
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
typeGuardNarrowsIndexedAccessOfAnyProperty.ts(51,7): error TS2532: Object is possibly 'undefined'.
2+
3+
4+
==== typeGuardNarrowsIndexedAccessOfAnyProperty.ts (1 errors) ====
5+
namespace Problem1 {
6+
declare const obj: { [key: string]: string | undefined };
7+
declare let key: "a";
8+
if (obj[key]) { obj[key].toUpperCase() } // should Ok
9+
}
10+
11+
namespace Problem2 {
12+
declare const obj: { [key: string]: string | undefined };
13+
declare const key: string;
14+
if (obj[key]) { obj[key].toUpperCase() } // should Ok
15+
}
16+
17+
namespace Problem3 {
18+
declare const obj: { a?: string, b?: string };
19+
declare const key: "a" | "b";
20+
if (obj[key]) { obj[key].toUpperCase() } // should Ok
21+
}
22+
23+
namespace Problem4 {
24+
function f<K extends string>(obj: { [P in K]?: string }, k: K) {
25+
const key: K = k;
26+
if (obj[key]) { obj[key].toUpperCase() } // should Ok
27+
}
28+
}
29+
30+
namespace Problem5 {
31+
declare const obj: { [key: string]: string | undefined };
32+
declare const key: string;
33+
if (obj[key]) {
34+
while(!!true) {
35+
obj[key].toUpperCase() // should Ok
36+
}
37+
}
38+
}
39+
40+
namespace Problem6 {
41+
declare const obj: { [key: string]: string | undefined };
42+
declare const key: string;
43+
while(!!true) {
44+
if (obj[key]) {
45+
obj[key].toUpperCase() // should Ok
46+
}
47+
}
48+
}
49+
50+
namespace Problem7 {
51+
declare const obj: { [key: string]: string | undefined };
52+
declare const key: string;
53+
if (obj[key]) {
54+
while(!!true) {
55+
obj[key].toUpperCase() // should error
56+
~~~~~~~~
57+
!!! error TS2532: Object is possibly 'undefined'.
58+
obj[key] = undefined
59+
}
60+
}
61+
}
62+

tests/baselines/reference/typeGuardNarrowsIndexedAccessOfAnyProperty.js

+58-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,39 @@ namespace Problem4 {
2424
const key: K = k;
2525
if (obj[key]) { obj[key].toUpperCase() } // should Ok
2626
}
27-
}
27+
}
28+
29+
namespace Problem5 {
30+
declare const obj: { [key: string]: string | undefined };
31+
declare const key: string;
32+
if (obj[key]) {
33+
while(!!true) {
34+
obj[key].toUpperCase() // should Ok
35+
}
36+
}
37+
}
38+
39+
namespace Problem6 {
40+
declare const obj: { [key: string]: string | undefined };
41+
declare const key: string;
42+
while(!!true) {
43+
if (obj[key]) {
44+
obj[key].toUpperCase() // should Ok
45+
}
46+
}
47+
}
48+
49+
namespace Problem7 {
50+
declare const obj: { [key: string]: string | undefined };
51+
declare const key: string;
52+
if (obj[key]) {
53+
while(!!true) {
54+
obj[key].toUpperCase() // should error
55+
obj[key] = undefined
56+
}
57+
}
58+
}
59+
2860

2961
//// [typeGuardNarrowsIndexedAccessOfAnyProperty.js]
3062
"use strict";
@@ -55,3 +87,28 @@ var Problem4;
5587
} // should Ok
5688
}
5789
})(Problem4 || (Problem4 = {}));
90+
var Problem5;
91+
(function (Problem5) {
92+
if (obj[key]) {
93+
while (!!true) {
94+
obj[key].toUpperCase(); // should Ok
95+
}
96+
}
97+
})(Problem5 || (Problem5 = {}));
98+
var Problem6;
99+
(function (Problem6) {
100+
while (!!true) {
101+
if (obj[key]) {
102+
obj[key].toUpperCase(); // should Ok
103+
}
104+
}
105+
})(Problem6 || (Problem6 = {}));
106+
var Problem7;
107+
(function (Problem7) {
108+
if (obj[key]) {
109+
while (!!true) {
110+
obj[key].toUpperCase(); // should error
111+
obj[key] = undefined;
112+
}
113+
}
114+
})(Problem7 || (Problem7 = {}));

tests/baselines/reference/typeGuardNarrowsIndexedAccessOfAnyProperty.symbols

+78
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,81 @@ namespace Problem4 {
8585
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
8686
}
8787
}
88+
89+
namespace Problem5 {
90+
>Problem5 : Symbol(Problem5, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 23, 1))
91+
92+
declare const obj: { [key: string]: string | undefined };
93+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 26, 15))
94+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 26, 24))
95+
96+
declare const key: string;
97+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 27, 15))
98+
99+
if (obj[key]) {
100+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 26, 15))
101+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 27, 15))
102+
103+
while(!!true) {
104+
obj[key].toUpperCase() // should Ok
105+
>obj[key].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
106+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 26, 15))
107+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 27, 15))
108+
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
109+
}
110+
}
111+
}
112+
113+
namespace Problem6 {
114+
>Problem6 : Symbol(Problem6, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 33, 1))
115+
116+
declare const obj: { [key: string]: string | undefined };
117+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 36, 15))
118+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 36, 24))
119+
120+
declare const key: string;
121+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 37, 15))
122+
123+
while(!!true) {
124+
if (obj[key]) {
125+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 36, 15))
126+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 37, 15))
127+
128+
obj[key].toUpperCase() // should Ok
129+
>obj[key].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
130+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 36, 15))
131+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 37, 15))
132+
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
133+
}
134+
}
135+
}
136+
137+
namespace Problem7 {
138+
>Problem7 : Symbol(Problem7, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 43, 1))
139+
140+
declare const obj: { [key: string]: string | undefined };
141+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 46, 15))
142+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 46, 24))
143+
144+
declare const key: string;
145+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 47, 15))
146+
147+
if (obj[key]) {
148+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 46, 15))
149+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 47, 15))
150+
151+
while(!!true) {
152+
obj[key].toUpperCase() // should error
153+
>obj[key].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
154+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 46, 15))
155+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 47, 15))
156+
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
157+
158+
obj[key] = undefined
159+
>obj : Symbol(obj, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 46, 15))
160+
>key : Symbol(key, Decl(typeGuardNarrowsIndexedAccessOfAnyProperty.ts, 47, 15))
161+
>undefined : Symbol(undefined)
162+
}
163+
}
164+
}
165+

tests/baselines/reference/typeGuardNarrowsIndexedAccessOfAnyProperty.types

+101
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,104 @@ namespace Problem4 {
9292
>toUpperCase : () => string
9393
}
9494
}
95+
96+
namespace Problem5 {
97+
>Problem5 : typeof Problem5
98+
99+
declare const obj: { [key: string]: string | undefined };
100+
>obj : { [key: string]: string | undefined; }
101+
>key : string
102+
103+
declare const key: string;
104+
>key : string
105+
106+
if (obj[key]) {
107+
>obj[key] : string | undefined
108+
>obj : { [key: string]: string | undefined; }
109+
>key : string
110+
111+
while(!!true) {
112+
>!!true : true
113+
>!true : false
114+
>true : true
115+
116+
obj[key].toUpperCase() // should Ok
117+
>obj[key].toUpperCase() : string
118+
>obj[key].toUpperCase : () => string
119+
>obj[key] : string
120+
>obj : { [key: string]: string | undefined; }
121+
>key : string
122+
>toUpperCase : () => string
123+
}
124+
}
125+
}
126+
127+
namespace Problem6 {
128+
>Problem6 : typeof Problem6
129+
130+
declare const obj: { [key: string]: string | undefined };
131+
>obj : { [key: string]: string | undefined; }
132+
>key : string
133+
134+
declare const key: string;
135+
>key : string
136+
137+
while(!!true) {
138+
>!!true : true
139+
>!true : false
140+
>true : true
141+
142+
if (obj[key]) {
143+
>obj[key] : string | undefined
144+
>obj : { [key: string]: string | undefined; }
145+
>key : string
146+
147+
obj[key].toUpperCase() // should Ok
148+
>obj[key].toUpperCase() : string
149+
>obj[key].toUpperCase : () => string
150+
>obj[key] : string
151+
>obj : { [key: string]: string | undefined; }
152+
>key : string
153+
>toUpperCase : () => string
154+
}
155+
}
156+
}
157+
158+
namespace Problem7 {
159+
>Problem7 : typeof Problem7
160+
161+
declare const obj: { [key: string]: string | undefined };
162+
>obj : { [key: string]: string | undefined; }
163+
>key : string
164+
165+
declare const key: string;
166+
>key : string
167+
168+
if (obj[key]) {
169+
>obj[key] : string | undefined
170+
>obj : { [key: string]: string | undefined; }
171+
>key : string
172+
173+
while(!!true) {
174+
>!!true : true
175+
>!true : false
176+
>true : true
177+
178+
obj[key].toUpperCase() // should error
179+
>obj[key].toUpperCase() : string
180+
>obj[key].toUpperCase : () => string
181+
>obj[key] : string | undefined
182+
>obj : { [key: string]: string | undefined; }
183+
>key : string
184+
>toUpperCase : () => string
185+
186+
obj[key] = undefined
187+
>obj[key] = undefined : undefined
188+
>obj[key] : string | undefined
189+
>obj : { [key: string]: string | undefined; }
190+
>key : string
191+
>undefined : undefined
192+
}
193+
}
194+
}
195+

tests/cases/compiler/typeGuardNarrowsIndexedAccessOfAnyProperty.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,35 @@ namespace Problem4 {
2222
const key: K = k;
2323
if (obj[key]) { obj[key].toUpperCase() } // should Ok
2424
}
25-
}
25+
}
26+
27+
namespace Problem5 {
28+
declare const obj: { [key: string]: string | undefined };
29+
declare const key: string;
30+
if (obj[key]) {
31+
while(!!true) {
32+
obj[key].toUpperCase() // should Ok
33+
}
34+
}
35+
}
36+
37+
namespace Problem6 {
38+
declare const obj: { [key: string]: string | undefined };
39+
declare const key: string;
40+
while(!!true) {
41+
if (obj[key]) {
42+
obj[key].toUpperCase() // should Ok
43+
}
44+
}
45+
}
46+
47+
namespace Problem7 {
48+
declare const obj: { [key: string]: string | undefined };
49+
declare const key: string;
50+
if (obj[key]) {
51+
while(!!true) {
52+
obj[key].toUpperCase() // should error
53+
obj[key] = undefined
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)