Skip to content

Commit 4632ed6

Browse files
authored
Merge pull request #21242 from Microsoft/fix-indexed-access-relation
Fix indexed access relation
2 parents 8c04540 + 485ec34 commit 4632ed6

10 files changed

+382
-51
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9637,7 +9637,7 @@ namespace ts {
96379637
}
96389638
else if (target.flags & TypeFlags.IndexedAccess) {
96399639
// A type S is related to a type T[K] if S is related to A[K], where K is string-like and
9640-
// A is the apparent type of T.
9640+
// A is the constraint of T.
96419641
const constraint = getConstraintOfIndexedAccess(<IndexedAccessType>target);
96429642
if (constraint) {
96439643
if (result = isRelatedTo(source, constraint, reportErrors)) {
@@ -9673,18 +9673,19 @@ namespace ts {
96739673
}
96749674
else if (source.flags & TypeFlags.IndexedAccess) {
96759675
// A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
9676-
// A is the apparent type of S.
9676+
// A is the constraint of S.
96779677
const constraint = getConstraintOfIndexedAccess(<IndexedAccessType>source);
96789678
if (constraint) {
96799679
if (result = isRelatedTo(constraint, target, reportErrors)) {
96809680
errorInfo = saveErrorInfo;
96819681
return result;
96829682
}
96839683
}
9684-
else if (target.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>source).indexType === (<IndexedAccessType>target).indexType) {
9685-
// if we have indexed access types with identical index types, see if relationship holds for
9686-
// the two object types.
9684+
else if (target.flags & TypeFlags.IndexedAccess) {
96879685
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
9686+
result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, reportErrors);
9687+
}
9688+
if (result) {
96889689
errorInfo = saveErrorInfo;
96899690
return result;
96909691
}

tests/baselines/reference/keyofAndIndexedAccess.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,19 @@ class AnotherSampleClass<T> extends SampleClass<T & Foo> {
552552
}
553553
}
554554
new AnotherSampleClass({});
555+
556+
// Positive repro from #17166
557+
function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void {
558+
for (let key in t) {
559+
key = k // ok, K ==> keyof T
560+
t[key] = tk; // ok, T[K] ==> T[keyof T]
561+
}
562+
}
563+
564+
// # 21185
565+
type Predicates<TaggedRecord> = {
566+
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T]
567+
}
555568

556569

557570
//// [keyofAndIndexedAccess.js]
@@ -928,6 +941,13 @@ var AnotherSampleClass = /** @class */ (function (_super) {
928941
return AnotherSampleClass;
929942
}(SampleClass));
930943
new AnotherSampleClass({});
944+
// Positive repro from #17166
945+
function f3(t, k, tk) {
946+
for (var key in t) {
947+
key = k; // ok, K ==> keyof T
948+
t[key] = tk; // ok, T[K] ==> T[keyof T]
949+
}
950+
}
931951

932952

933953
//// [keyofAndIndexedAccess.d.ts]
@@ -1188,3 +1208,7 @@ declare class AnotherSampleClass<T> extends SampleClass<T & Foo> {
11881208
constructor(props: T);
11891209
brokenMethod(): void;
11901210
}
1211+
declare function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void;
1212+
declare type Predicates<TaggedRecord> = {
1213+
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T];
1214+
};

tests/baselines/reference/keyofAndIndexedAccess.symbols

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,3 +1962,48 @@ class AnotherSampleClass<T> extends SampleClass<T & Foo> {
19621962
new AnotherSampleClass({});
19631963
>AnotherSampleClass : Symbol(AnotherSampleClass, Decl(keyofAndIndexedAccess.ts, 540, 54))
19641964

1965+
// Positive repro from #17166
1966+
function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void {
1967+
>f3 : Symbol(f3, Decl(keyofAndIndexedAccess.ts, 552, 27))
1968+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 555, 12))
1969+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 555, 14))
1970+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 555, 12))
1971+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 555, 34))
1972+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 555, 12))
1973+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 555, 39))
1974+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 555, 14))
1975+
>tk : Symbol(tk, Decl(keyofAndIndexedAccess.ts, 555, 45))
1976+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 555, 12))
1977+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 555, 14))
1978+
1979+
for (let key in t) {
1980+
>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 556, 12))
1981+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 555, 34))
1982+
1983+
key = k // ok, K ==> keyof T
1984+
>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 556, 12))
1985+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 555, 39))
1986+
1987+
t[key] = tk; // ok, T[K] ==> T[keyof T]
1988+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 555, 34))
1989+
>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 556, 12))
1990+
>tk : Symbol(tk, Decl(keyofAndIndexedAccess.ts, 555, 45))
1991+
}
1992+
}
1993+
1994+
// # 21185
1995+
type Predicates<TaggedRecord> = {
1996+
>Predicates : Symbol(Predicates, Decl(keyofAndIndexedAccess.ts, 560, 1))
1997+
>TaggedRecord : Symbol(TaggedRecord, Decl(keyofAndIndexedAccess.ts, 563, 16))
1998+
1999+
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T]
2000+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 564, 3))
2001+
>TaggedRecord : Symbol(TaggedRecord, Decl(keyofAndIndexedAccess.ts, 563, 16))
2002+
>variant : Symbol(variant, Decl(keyofAndIndexedAccess.ts, 564, 30))
2003+
>TaggedRecord : Symbol(TaggedRecord, Decl(keyofAndIndexedAccess.ts, 563, 16))
2004+
>TaggedRecord : Symbol(TaggedRecord, Decl(keyofAndIndexedAccess.ts, 563, 16))
2005+
>variant : Symbol(variant, Decl(keyofAndIndexedAccess.ts, 564, 30))
2006+
>TaggedRecord : Symbol(TaggedRecord, Decl(keyofAndIndexedAccess.ts, 563, 16))
2007+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 564, 3))
2008+
}
2009+

tests/baselines/reference/keyofAndIndexedAccess.types

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,3 +2294,51 @@ new AnotherSampleClass({});
22942294
>AnotherSampleClass : typeof AnotherSampleClass
22952295
>{} : {}
22962296

2297+
// Positive repro from #17166
2298+
function f3<T, K extends keyof T>(t: T, k: K, tk: T[K]): void {
2299+
>f3 : <T, K extends keyof T>(t: T, k: K, tk: T[K]) => void
2300+
>T : T
2301+
>K : K
2302+
>T : T
2303+
>t : T
2304+
>T : T
2305+
>k : K
2306+
>K : K
2307+
>tk : T[K]
2308+
>T : T
2309+
>K : K
2310+
2311+
for (let key in t) {
2312+
>key : keyof T
2313+
>t : T
2314+
2315+
key = k // ok, K ==> keyof T
2316+
>key = k : K
2317+
>key : keyof T
2318+
>k : K
2319+
2320+
t[key] = tk; // ok, T[K] ==> T[keyof T]
2321+
>t[key] = tk : T[K]
2322+
>t[key] : T[keyof T]
2323+
>t : T
2324+
>key : keyof T
2325+
>tk : T[K]
2326+
}
2327+
}
2328+
2329+
// # 21185
2330+
type Predicates<TaggedRecord> = {
2331+
>Predicates : Predicates<TaggedRecord>
2332+
>TaggedRecord : TaggedRecord
2333+
2334+
[T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T]
2335+
>T : T
2336+
>TaggedRecord : TaggedRecord
2337+
>variant : TaggedRecord[keyof TaggedRecord]
2338+
>TaggedRecord : TaggedRecord
2339+
>TaggedRecord : TaggedRecord
2340+
>variant : any
2341+
>TaggedRecord : TaggedRecord
2342+
>T : T
2343+
}
2344+

tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,21 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(76,5): error
2727
Type 'T' is not assignable to type 'T & U'.
2828
Type 'T' is not assignable to type 'U'.
2929
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error TS2322: Type 'keyof (T & U)' is not assignable to type 'keyof (T | U)'.
30-
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(84,9): error TS2322: Type 'keyof T' is not assignable to type 'K'.
31-
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(85,9): error TS2322: Type 'T[keyof T]' is not assignable to type 'T[K]'.
30+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(86,9): error TS2322: Type 'keyof T' is not assignable to type 'K'.
31+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(88,9): error TS2322: Type 'T[keyof T]' is not assignable to type 'T[K]'.
32+
Type 'keyof T' is not assignable to type 'K'.
33+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(91,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
34+
Type 'T' is not assignable to type 'U'.
35+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(94,5): error TS2322: Type 'T[J]' is not assignable to type 'U[J]'.
36+
Type 'T' is not assignable to type 'U'.
37+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(97,5): error TS2322: Type 'T[K]' is not assignable to type 'T[J]'.
38+
Type 'K' is not assignable to type 'J'.
39+
Type 'keyof T' is not assignable to type 'J'.
40+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(100,5): error TS2322: Type 'T[K]' is not assignable to type 'U[J]'.
41+
Type 'T' is not assignable to type 'U'.
3242

3343

34-
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (27 errors) ====
44+
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (31 errors) ====
3545
class Shape {
3646
name: string;
3747
width: number;
@@ -167,15 +177,42 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(85,9): error
167177
}
168178

169179
// Repro from #17166
170-
function f3<T, K extends keyof T>(obj: T, k: K, value: T[K]): void {
171-
for (let key in obj) {
180+
function f3<T, K extends keyof T, U extends T, J extends K>(
181+
t: T, k: K, tk: T[K], u: U, j: J, uk: U[K], tj: T[J], uj: U[J]): void {
182+
for (let key in t) {
183+
key = k // ok, K ==> keyof T
172184
k = key // error, keyof T =/=> K
173185
~
174186
!!! error TS2322: Type 'keyof T' is not assignable to type 'K'.
175-
value = obj[key]; // error, T[keyof T] =/=> T[K]
176-
~~~~~
187+
t[key] = tk; // ok, T[K] ==> T[keyof T]
188+
tk = t[key]; // error, T[keyof T] =/=> T[K]
189+
~~
177190
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'T[K]'.
191+
!!! error TS2322: Type 'keyof T' is not assignable to type 'K'.
178192
}
179-
}
193+
tk = uk;
194+
uk = tk; // error
195+
~~
196+
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
197+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
198+
199+
tj = uj;
200+
uj = tj; // error
201+
~~
202+
!!! error TS2322: Type 'T[J]' is not assignable to type 'U[J]'.
203+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
180204

205+
tk = tj;
206+
tj = tk; // error
207+
~~
208+
!!! error TS2322: Type 'T[K]' is not assignable to type 'T[J]'.
209+
!!! error TS2322: Type 'K' is not assignable to type 'J'.
210+
!!! error TS2322: Type 'keyof T' is not assignable to type 'J'.
211+
212+
tk = uj;
213+
uj = tk; // error
214+
~~
215+
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[J]'.
216+
!!! error TS2322: Type 'T' is not assignable to type 'U'.
217+
}
181218

tests/baselines/reference/keyofAndIndexedAccessErrors.js

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,26 @@ function f20<T, U>(k1: keyof (T | U), k2: keyof (T & U), o1: T | U, o2: T & U) {
8080
}
8181

8282
// Repro from #17166
83-
function f3<T, K extends keyof T>(obj: T, k: K, value: T[K]): void {
84-
for (let key in obj) {
83+
function f3<T, K extends keyof T, U extends T, J extends K>(
84+
t: T, k: K, tk: T[K], u: U, j: J, uk: U[K], tj: T[J], uj: U[J]): void {
85+
for (let key in t) {
86+
key = k // ok, K ==> keyof T
8587
k = key // error, keyof T =/=> K
86-
value = obj[key]; // error, T[keyof T] =/=> T[K]
88+
t[key] = tk; // ok, T[K] ==> T[keyof T]
89+
tk = t[key]; // error, T[keyof T] =/=> T[K]
8790
}
88-
}
91+
tk = uk;
92+
uk = tk; // error
93+
94+
tj = uj;
95+
uj = tj; // error
8996

97+
tk = tj;
98+
tj = tk; // error
99+
100+
tk = uj;
101+
uj = tk; // error
102+
}
90103

91104

92105
//// [keyofAndIndexedAccessErrors.js]
@@ -120,9 +133,19 @@ function f20(k1, k2, o1, o2) {
120133
k2 = k1;
121134
}
122135
// Repro from #17166
123-
function f3(obj, k, value) {
124-
for (var key in obj) {
136+
function f3(t, k, tk, u, j, uk, tj, uj) {
137+
for (var key in t) {
138+
key = k; // ok, K ==> keyof T
125139
k = key; // error, keyof T =/=> K
126-
value = obj[key]; // error, T[keyof T] =/=> T[K]
140+
t[key] = tk; // ok, T[K] ==> T[keyof T]
141+
tk = t[key]; // error, T[keyof T] =/=> T[K]
127142
}
143+
tk = uk;
144+
uk = tk; // error
145+
tj = uj;
146+
uj = tj; // error
147+
tk = tj;
148+
tj = tk; // error
149+
tk = uj;
150+
uj = tk; // error
128151
}

0 commit comments

Comments
 (0)