Skip to content

Commit e601333

Browse files
authored
Merge pull request #31537 from microsoft/fixIndexedAccessConstraint
Fix indexed access constraint
2 parents 6a559e3 + cd7a14a commit e601333

File tree

6 files changed

+98
-4
lines changed

6 files changed

+98
-4
lines changed

src/compiler/checker.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -7657,15 +7657,20 @@ namespace ts {
76577657
return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined;
76587658
}
76597659

7660+
function getSimplifiedTypeOrConstraint(type: Type) {
7661+
const simplified = getSimplifiedType(type, /*writing*/ false);
7662+
return simplified !== type ? simplified : getConstraintOfType(type);
7663+
}
7664+
76607665
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
7661-
const indexConstraint = getConstraintOfType(type.indexType);
7666+
const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType);
76627667
if (indexConstraint && indexConstraint !== type.indexType) {
76637668
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint);
76647669
if (indexedAccess) {
76657670
return indexedAccess;
76667671
}
76677672
}
7668-
const objectConstraint = getConstraintOfType(type.objectType);
7673+
const objectConstraint = getSimplifiedTypeOrConstraint(type.objectType);
76697674
if (objectConstraint && objectConstraint !== type.objectType) {
76707675
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType);
76717676
}
@@ -13061,8 +13066,7 @@ namespace ts {
1306113066
}
1306213067
// A type S is assignable to keyof T if S is assignable to keyof C, where C is the
1306313068
// simplified form of T or, if T doesn't simplify, the constraint of T.
13064-
const simplified = getSimplifiedType((<IndexType>target).type, /*writing*/ false);
13065-
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
13069+
const constraint = getSimplifiedTypeOrConstraint((<IndexType>target).type);
1306613070
if (constraint) {
1306713071
// We require Ternary.True here such that circular constraints don't cause
1306813072
// false positives. For example, given 'T extends { [K in keyof T]: string }',

tests/baselines/reference/keyofAndIndexedAccess2.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,14 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
228228
this["a"] = "b";
229229
}
230230
}
231+
232+
// Repro from #31385
233+
234+
type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
235+
236+
type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
237+
238+
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
239+
240+
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
231241

tests/baselines/reference/keyofAndIndexedAccess2.js

+10
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ export class c {
145145
this["a"] = "b";
146146
}
147147
}
148+
149+
// Repro from #31385
150+
151+
type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
152+
153+
type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
154+
155+
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
156+
157+
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
148158

149159

150160
//// [keyofAndIndexedAccess2.js]

tests/baselines/reference/keyofAndIndexedAccess2.symbols

+44
Original file line numberDiff line numberDiff line change
@@ -517,3 +517,47 @@ export class c {
517517
}
518518
}
519519

520+
// Repro from #31385
521+
522+
type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
523+
>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1))
524+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))
525+
>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 149, 17))
526+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34))
527+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))
528+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34))
529+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))
530+
531+
type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
532+
>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64))
533+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))
534+
>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 151, 17))
535+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34))
536+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))
537+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34))
538+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))
539+
540+
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
541+
>Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 151, 66))
542+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
543+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
544+
>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1))
545+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
546+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35))
547+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
548+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
549+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
550+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35))
551+
552+
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
553+
>Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 153, 60))
554+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
555+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
556+
>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64))
557+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
558+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35))
559+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
560+
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
561+
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
562+
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35))
563+

tests/baselines/reference/keyofAndIndexedAccess2.types

+16
Original file line numberDiff line numberDiff line change
@@ -517,3 +517,19 @@ export class c {
517517
}
518518
}
519519

520+
// Repro from #31385
521+
522+
type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
523+
>Foo : Foo<T>
524+
>key : string
525+
526+
type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
527+
>Bar : Bar<T>
528+
>key : string
529+
530+
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
531+
>Baz : Baz<T, Q>
532+
533+
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
534+
>Qux : Qux<T, Q>
535+

tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts

+10
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,13 @@ export class c {
147147
this["a"] = "b";
148148
}
149149
}
150+
151+
// Repro from #31385
152+
153+
type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
154+
155+
type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
156+
157+
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
158+
159+
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };

0 commit comments

Comments
 (0)