Skip to content

Commit 01527ce

Browse files
authored
Revert "Always substitute indexed generic mapped type when getting constraint from indexed access" (#57202)
1 parent 3c9aea3 commit 01527ce

File tree

6 files changed

+336
-113
lines changed

6 files changed

+336
-113
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14230,7 +14230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1423014230
}
1423114231

1423214232
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
14233-
if (isMappedTypeGenericIndexedAccess(type) || isGenericMappedType(type.objectType)) {
14233+
if (isMappedTypeGenericIndexedAccess(type)) {
1423414234
// For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic,
1423514235
// we substitute an instantiation of E where P is replaced with X.
1423614236
return substituteIndexedMappedType(type.objectType as MappedType, type.indexType);
Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,18 @@
11
mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2<K>[`get${K}`]' is not assignable to type '{ a: K; }'.
2-
Type '{ a: `get${K}`; }' is not assignable to type '{ a: K; }'.
3-
Types of property 'a' are incompatible.
4-
Type '`get${K}`' is not assignable to type 'K'.
5-
'`get${K}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
6-
Type '`get${string}`' is not assignable to type 'K'.
7-
'`get${string}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
2+
Type 'Mapped2<K>[`get${string}`]' is not assignable to type '{ a: K; }'.
83
mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
9-
Type '{ a: Uppercase<K>; }' is not assignable to type '{ a: K; }'.
10-
Types of property 'a' are incompatible.
11-
Type 'Uppercase<K>' is not assignable to type 'K'.
12-
'Uppercase<K>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
13-
Type 'Uppercase<string>' is not assignable to type 'K'.
14-
'Uppercase<string>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
15-
Type 'string' is not assignable to type 'K'.
16-
'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
17-
mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'.
18-
'Foo<T>[`get${T}`]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
19-
Type '`get${T}`' is not assignable to type 'T'.
20-
'`get${T}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
21-
Type '`get${string}`' is not assignable to type 'T'.
22-
'`get${string}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
4+
Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
5+
Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
6+
mappedTypeConstraints2.ts(42,7): error TS2322: Type 'Mapped6<K>[keyof Mapped6<K>]' is not assignable to type '`_${string}`'.
7+
Type 'Mapped6<K>[string] | Mapped6<K>[number] | Mapped6<K>[symbol]' is not assignable to type '`_${string}`'.
8+
Type 'Mapped6<K>[string]' is not assignable to type '`_${string}`'.
9+
mappedTypeConstraints2.ts(51,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'.
10+
'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.
11+
mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${K}`]' is not assignable to type 'true'.
12+
Type 'ObjectWithUnderscoredKeys<K>[`_${string}`]' is not assignable to type 'true'.
2313

2414

25-
==== mappedTypeConstraints2.ts (3 errors) ====
15+
==== mappedTypeConstraints2.ts (5 errors) ====
2616
type Mapped1<K extends string> = { [P in K]: { a: P } };
2717

2818
function f1<K extends string>(obj: Mapped1<K>, key: K) {
@@ -35,12 +25,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
3525
const x: { a: K } = obj[key]; // Error
3626
~
3727
!!! error TS2322: Type 'Mapped2<K>[`get${K}`]' is not assignable to type '{ a: K; }'.
38-
!!! error TS2322: Type '{ a: `get${K}`; }' is not assignable to type '{ a: K; }'.
39-
!!! error TS2322: Types of property 'a' are incompatible.
40-
!!! error TS2322: Type '`get${K}`' is not assignable to type 'K'.
41-
!!! error TS2322: '`get${K}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
42-
!!! error TS2322: Type '`get${string}`' is not assignable to type 'K'.
43-
!!! error TS2322: '`get${string}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
28+
!!! error TS2322: Type 'Mapped2<K>[`get${string}`]' is not assignable to type '{ a: K; }'.
4429
}
4530

4631
type Mapped3<K extends string> = { [P in K as Uppercase<P>]: { a: P } };
@@ -49,14 +34,38 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
4934
const x: { a: K } = obj[key]; // Error
5035
~
5136
!!! error TS2322: Type 'Mapped3<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
52-
!!! error TS2322: Type '{ a: Uppercase<K>; }' is not assignable to type '{ a: K; }'.
53-
!!! error TS2322: Types of property 'a' are incompatible.
54-
!!! error TS2322: Type 'Uppercase<K>' is not assignable to type 'K'.
55-
!!! error TS2322: 'Uppercase<K>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
56-
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'K'.
57-
!!! error TS2322: 'Uppercase<string>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
58-
!!! error TS2322: Type 'string' is not assignable to type 'K'.
59-
!!! error TS2322: 'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
37+
!!! error TS2322: Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
38+
!!! error TS2322: Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
39+
}
40+
41+
type Mapped4<K extends `_${string}`> = {
42+
[P in K]: P;
43+
};
44+
45+
function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>) {
46+
let s: `_${string}` = obj[key];
47+
}
48+
49+
type Mapped5<K extends string> = {
50+
[P in K as P extends `_${string}` ? P : never]: P;
51+
};
52+
53+
function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>) {
54+
let s: `_${string}` = obj[key];
55+
}
56+
57+
// repro from #53066#issuecomment-1913384757
58+
59+
type Mapped6<K extends string> = {
60+
[P in K as `_${P}`]: P;
61+
};
62+
63+
function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>) {
64+
let s: `_${string}` = obj[key]; // Error
65+
~
66+
!!! error TS2322: Type 'Mapped6<K>[keyof Mapped6<K>]' is not assignable to type '`_${string}`'.
67+
!!! error TS2322: Type 'Mapped6<K>[string] | Mapped6<K>[number] | Mapped6<K>[symbol]' is not assignable to type '`_${string}`'.
68+
!!! error TS2322: Type 'Mapped6<K>[string]' is not assignable to type '`_${string}`'.
6069
}
6170

6271
// Repro from #47794
@@ -68,11 +77,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
6877
const get = <T extends string>(t: T, foo: Foo<T>): T => foo[`get${t}`]; // Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'
6978
~~~~~~~~~~~~~~
7079
!!! error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'.
71-
!!! error TS2322: 'Foo<T>[`get${T}`]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
72-
!!! error TS2322: Type '`get${T}`' is not assignable to type 'T'.
73-
!!! error TS2322: '`get${T}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
74-
!!! error TS2322: Type '`get${string}`' is not assignable to type 'T'.
75-
!!! error TS2322: '`get${string}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'.
80+
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.
7681

7782
// Repro from #48626
7883

@@ -103,6 +108,9 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
103108
};
104109

105110
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
106-
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
111+
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
112+
~~~~~~~~~~~~
113+
!!! error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${K}`]' is not assignable to type 'true'.
114+
!!! error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${string}`]' is not assignable to type 'true'.
107115
}
108116

tests/baselines/reference/mappedTypeConstraints2.js

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,32 @@ function f3<K extends string>(obj: Mapped3<K>, key: Uppercase<K>) {
1919
const x: { a: K } = obj[key]; // Error
2020
}
2121

22+
type Mapped4<K extends `_${string}`> = {
23+
[P in K]: P;
24+
};
25+
26+
function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>) {
27+
let s: `_${string}` = obj[key];
28+
}
29+
30+
type Mapped5<K extends string> = {
31+
[P in K as P extends `_${string}` ? P : never]: P;
32+
};
33+
34+
function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>) {
35+
let s: `_${string}` = obj[key];
36+
}
37+
38+
// repro from #53066#issuecomment-1913384757
39+
40+
type Mapped6<K extends string> = {
41+
[P in K as `_${P}`]: P;
42+
};
43+
44+
function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>) {
45+
let s: `_${string}` = obj[key]; // Error
46+
}
47+
2248
// Repro from #47794
2349

2450
type Foo<T extends string> = {
@@ -56,7 +82,7 @@ type ObjectWithUnderscoredKeys<K extends string> = {
5682
};
5783

5884
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
59-
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
85+
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
6086
}
6187

6288

@@ -71,6 +97,15 @@ function f2(obj, key) {
7197
function f3(obj, key) {
7298
const x = obj[key]; // Error
7399
}
100+
function f4(obj, key) {
101+
let s = obj[key];
102+
}
103+
function f5(obj, key) {
104+
let s = obj[key];
105+
}
106+
function f6(obj, key) {
107+
let s = obj[key]; // Error
108+
}
74109
const get = (t, foo) => foo[`get${t}`]; // Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'
75110
function validate(obj, bounds) {
76111
for (const [key, val] of Object.entries(obj)) {
@@ -84,7 +119,7 @@ function validate(obj, bounds) {
84119
return true;
85120
}
86121
function genericTest(objectWithUnderscoredKeys, key) {
87-
const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`];
122+
const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
88123
}
89124

90125

@@ -107,6 +142,18 @@ type Mapped3<K extends string> = {
107142
};
108143
};
109144
declare function f3<K extends string>(obj: Mapped3<K>, key: Uppercase<K>): void;
145+
type Mapped4<K extends `_${string}`> = {
146+
[P in K]: P;
147+
};
148+
declare function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>): void;
149+
type Mapped5<K extends string> = {
150+
[P in K as P extends `_${string}` ? P : never]: P;
151+
};
152+
declare function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>): void;
153+
type Mapped6<K extends string> = {
154+
[P in K as `_${P}`]: P;
155+
};
156+
declare function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>): void;
110157
type Foo<T extends string> = {
111158
[RemappedT in T as `get${RemappedT}`]: RemappedT;
112159
};

0 commit comments

Comments
 (0)