Skip to content

Commit 5e4fcfb

Browse files
authored
Add instantiation rules for reverse mapped types (#42449)
* Add instantiation rules for reverse mapped types * Add smaller example of same issue
1 parent cfb9a25 commit 5e4fcfb

5 files changed

+442
-1
lines changed

src/compiler/checker.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -16158,6 +16158,9 @@ namespace ts {
1615816158
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
1615916159
return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((<TypeReference>type).target, newTypeArguments) : type;
1616016160
}
16161+
if (objectFlags & ObjectFlags.ReverseMapped) {
16162+
return instantiateReverseMappedType(type as ReverseMappedType, mapper);
16163+
}
1616116164
return getObjectTypeInstantiation(<TypeReference | AnonymousType | MappedType>type, mapper, aliasSymbol, aliasTypeArguments);
1616216165
}
1616316166
return type;
@@ -16208,6 +16211,26 @@ namespace ts {
1620816211
return type;
1620916212
}
1621016213

16214+
function instantiateReverseMappedType(type: ReverseMappedType, mapper: TypeMapper) {
16215+
const innerMappedType = instantiateType(type.mappedType, mapper);
16216+
if (!(getObjectFlags(innerMappedType) & ObjectFlags.Mapped)) {
16217+
return type;
16218+
}
16219+
const innerIndexType = instantiateType(type.constraintType, mapper);
16220+
if (!(innerIndexType.flags & TypeFlags.Index)) {
16221+
return type;
16222+
}
16223+
const instantiated = inferTypeForHomomorphicMappedType(
16224+
instantiateType(type.source, mapper),
16225+
innerMappedType as MappedType,
16226+
innerIndexType as IndexType
16227+
);
16228+
if (instantiated) {
16229+
return instantiated;
16230+
}
16231+
return type; // Nested invocation of `inferTypeForHomomorphicMappedType` or the `source` instantiated into something unmappable
16232+
}
16233+
1621116234
function getPermissiveInstantiation(type: Type) {
1621216235
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
1621316236
type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper));
@@ -20674,7 +20697,7 @@ namespace ts {
2067420697
type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && (
2067520698
objectFlags & ObjectFlags.Reference && ((<TypeReference>type).node || forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables)) ||
2067620699
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
20677-
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ObjectRestType)) ||
20700+
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType)) ||
2067820701
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((<UnionOrIntersectionType>type).types, couldContainTypeVariables));
2067920702
if (type.flags & TypeFlags.ObjectFlagsType) {
2068020703
(<ObjectFlagsType>type).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//// [genericFunctionsAndConditionalInference.ts]
2+
type Boxified<T> = { [P in keyof T]: { value: T[P]} };
3+
4+
declare function unboxify<T>(obj: Boxified<T>): T;
5+
6+
function foo<U, V>(obj: { u: { value: U }, v: { value: V } }) {
7+
return unboxify(obj);
8+
}
9+
10+
let qq = foo({ u: { value: 10 }, v: { value: 'hello'} }); // { u: U, v: V } but should be { u: number, v: string }
11+
12+
// From #42385
13+
interface Targets<A> {
14+
left: A
15+
right: A
16+
}
17+
type Target = keyof Targets<any>
18+
type Result<F extends Target, A> = Targets<A>[F]
19+
20+
type LR<F extends Target, L, R> = [F] extends ["left"] ? L : R
21+
22+
interface Ops<F extends Target> {
23+
_f: F
24+
str: Result<F, string>
25+
num: Result<F, number>
26+
lr<I, O>(a: Result<F, I>, o: Result<F, O>): Result<F, LR<F, I, O>>
27+
dict: <P>(p: {[k in keyof P]: Result<F, P[k]>}) => Result<F, P>
28+
}
29+
const left: Ops<"left"> = {} as any
30+
const right: Ops<"right"> = {} as any
31+
32+
const ok = <F extends Target>(at: Ops<F>) => ({lr: at.lr(at.str, at.num)})
33+
const orphaned = <F extends Target>(at: Ops<F>) => at.dict(ok(at))
34+
35+
const leftOk = ok(left)
36+
const leftOrphaned = orphaned(left)
37+
38+
const rightOk = ok(right)
39+
const rightOrphaned = orphaned(right)
40+
41+
//// [genericFunctionsAndConditionalInference.js]
42+
function foo(obj) {
43+
return unboxify(obj);
44+
}
45+
var qq = foo({ u: { value: 10 }, v: { value: 'hello' } }); // { u: U, v: V } but should be { u: number, v: string }
46+
var left = {};
47+
var right = {};
48+
var ok = function (at) { return ({ lr: at.lr(at.str, at.num) }); };
49+
var orphaned = function (at) { return at.dict(ok(at)); };
50+
var leftOk = ok(left);
51+
var leftOrphaned = orphaned(left);
52+
var rightOk = ok(right);
53+
var rightOrphaned = orphaned(right);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
=== tests/cases/compiler/genericFunctionsAndConditionalInference.ts ===
2+
type Boxified<T> = { [P in keyof T]: { value: T[P]} };
3+
>Boxified : Symbol(Boxified, Decl(genericFunctionsAndConditionalInference.ts, 0, 0))
4+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 0, 14))
5+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 0, 22))
6+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 0, 14))
7+
>value : Symbol(value, Decl(genericFunctionsAndConditionalInference.ts, 0, 38))
8+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 0, 14))
9+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 0, 22))
10+
11+
declare function unboxify<T>(obj: Boxified<T>): T;
12+
>unboxify : Symbol(unboxify, Decl(genericFunctionsAndConditionalInference.ts, 0, 54))
13+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 2, 26))
14+
>obj : Symbol(obj, Decl(genericFunctionsAndConditionalInference.ts, 2, 29))
15+
>Boxified : Symbol(Boxified, Decl(genericFunctionsAndConditionalInference.ts, 0, 0))
16+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 2, 26))
17+
>T : Symbol(T, Decl(genericFunctionsAndConditionalInference.ts, 2, 26))
18+
19+
function foo<U, V>(obj: { u: { value: U }, v: { value: V } }) {
20+
>foo : Symbol(foo, Decl(genericFunctionsAndConditionalInference.ts, 2, 50))
21+
>U : Symbol(U, Decl(genericFunctionsAndConditionalInference.ts, 4, 13))
22+
>V : Symbol(V, Decl(genericFunctionsAndConditionalInference.ts, 4, 15))
23+
>obj : Symbol(obj, Decl(genericFunctionsAndConditionalInference.ts, 4, 19))
24+
>u : Symbol(u, Decl(genericFunctionsAndConditionalInference.ts, 4, 25))
25+
>value : Symbol(value, Decl(genericFunctionsAndConditionalInference.ts, 4, 30))
26+
>U : Symbol(U, Decl(genericFunctionsAndConditionalInference.ts, 4, 13))
27+
>v : Symbol(v, Decl(genericFunctionsAndConditionalInference.ts, 4, 42))
28+
>value : Symbol(value, Decl(genericFunctionsAndConditionalInference.ts, 4, 47))
29+
>V : Symbol(V, Decl(genericFunctionsAndConditionalInference.ts, 4, 15))
30+
31+
return unboxify(obj);
32+
>unboxify : Symbol(unboxify, Decl(genericFunctionsAndConditionalInference.ts, 0, 54))
33+
>obj : Symbol(obj, Decl(genericFunctionsAndConditionalInference.ts, 4, 19))
34+
}
35+
36+
let qq = foo({ u: { value: 10 }, v: { value: 'hello'} }); // { u: U, v: V } but should be { u: number, v: string }
37+
>qq : Symbol(qq, Decl(genericFunctionsAndConditionalInference.ts, 8, 3))
38+
>foo : Symbol(foo, Decl(genericFunctionsAndConditionalInference.ts, 2, 50))
39+
>u : Symbol(u, Decl(genericFunctionsAndConditionalInference.ts, 8, 14))
40+
>value : Symbol(value, Decl(genericFunctionsAndConditionalInference.ts, 8, 19))
41+
>v : Symbol(v, Decl(genericFunctionsAndConditionalInference.ts, 8, 32))
42+
>value : Symbol(value, Decl(genericFunctionsAndConditionalInference.ts, 8, 37))
43+
44+
// From #42385
45+
interface Targets<A> {
46+
>Targets : Symbol(Targets, Decl(genericFunctionsAndConditionalInference.ts, 8, 57))
47+
>A : Symbol(A, Decl(genericFunctionsAndConditionalInference.ts, 11, 18))
48+
49+
left: A
50+
>left : Symbol(Targets.left, Decl(genericFunctionsAndConditionalInference.ts, 11, 22))
51+
>A : Symbol(A, Decl(genericFunctionsAndConditionalInference.ts, 11, 18))
52+
53+
right: A
54+
>right : Symbol(Targets.right, Decl(genericFunctionsAndConditionalInference.ts, 12, 11))
55+
>A : Symbol(A, Decl(genericFunctionsAndConditionalInference.ts, 11, 18))
56+
}
57+
type Target = keyof Targets<any>
58+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
59+
>Targets : Symbol(Targets, Decl(genericFunctionsAndConditionalInference.ts, 8, 57))
60+
61+
type Result<F extends Target, A> = Targets<A>[F]
62+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
63+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 16, 12))
64+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
65+
>A : Symbol(A, Decl(genericFunctionsAndConditionalInference.ts, 16, 29))
66+
>Targets : Symbol(Targets, Decl(genericFunctionsAndConditionalInference.ts, 8, 57))
67+
>A : Symbol(A, Decl(genericFunctionsAndConditionalInference.ts, 16, 29))
68+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 16, 12))
69+
70+
type LR<F extends Target, L, R> = [F] extends ["left"] ? L : R
71+
>LR : Symbol(LR, Decl(genericFunctionsAndConditionalInference.ts, 16, 48))
72+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 18, 8))
73+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
74+
>L : Symbol(L, Decl(genericFunctionsAndConditionalInference.ts, 18, 25))
75+
>R : Symbol(R, Decl(genericFunctionsAndConditionalInference.ts, 18, 28))
76+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 18, 8))
77+
>L : Symbol(L, Decl(genericFunctionsAndConditionalInference.ts, 18, 25))
78+
>R : Symbol(R, Decl(genericFunctionsAndConditionalInference.ts, 18, 28))
79+
80+
interface Ops<F extends Target> {
81+
>Ops : Symbol(Ops, Decl(genericFunctionsAndConditionalInference.ts, 18, 62))
82+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
83+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
84+
85+
_f: F
86+
>_f : Symbol(Ops._f, Decl(genericFunctionsAndConditionalInference.ts, 20, 33))
87+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
88+
89+
str: Result<F, string>
90+
>str : Symbol(Ops.str, Decl(genericFunctionsAndConditionalInference.ts, 21, 9))
91+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
92+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
93+
94+
num: Result<F, number>
95+
>num : Symbol(Ops.num, Decl(genericFunctionsAndConditionalInference.ts, 22, 26))
96+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
97+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
98+
99+
lr<I, O>(a: Result<F, I>, o: Result<F, O>): Result<F, LR<F, I, O>>
100+
>lr : Symbol(Ops.lr, Decl(genericFunctionsAndConditionalInference.ts, 23, 26))
101+
>I : Symbol(I, Decl(genericFunctionsAndConditionalInference.ts, 24, 7))
102+
>O : Symbol(O, Decl(genericFunctionsAndConditionalInference.ts, 24, 9))
103+
>a : Symbol(a, Decl(genericFunctionsAndConditionalInference.ts, 24, 13))
104+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
105+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
106+
>I : Symbol(I, Decl(genericFunctionsAndConditionalInference.ts, 24, 7))
107+
>o : Symbol(o, Decl(genericFunctionsAndConditionalInference.ts, 24, 29))
108+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
109+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
110+
>O : Symbol(O, Decl(genericFunctionsAndConditionalInference.ts, 24, 9))
111+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
112+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
113+
>LR : Symbol(LR, Decl(genericFunctionsAndConditionalInference.ts, 16, 48))
114+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
115+
>I : Symbol(I, Decl(genericFunctionsAndConditionalInference.ts, 24, 7))
116+
>O : Symbol(O, Decl(genericFunctionsAndConditionalInference.ts, 24, 9))
117+
118+
dict: <P>(p: {[k in keyof P]: Result<F, P[k]>}) => Result<F, P>
119+
>dict : Symbol(Ops.dict, Decl(genericFunctionsAndConditionalInference.ts, 24, 70))
120+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 25, 11))
121+
>p : Symbol(p, Decl(genericFunctionsAndConditionalInference.ts, 25, 14))
122+
>k : Symbol(k, Decl(genericFunctionsAndConditionalInference.ts, 25, 19))
123+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 25, 11))
124+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
125+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
126+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 25, 11))
127+
>k : Symbol(k, Decl(genericFunctionsAndConditionalInference.ts, 25, 19))
128+
>Result : Symbol(Result, Decl(genericFunctionsAndConditionalInference.ts, 15, 32))
129+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 20, 14))
130+
>P : Symbol(P, Decl(genericFunctionsAndConditionalInference.ts, 25, 11))
131+
}
132+
const left: Ops<"left"> = {} as any
133+
>left : Symbol(left, Decl(genericFunctionsAndConditionalInference.ts, 27, 5))
134+
>Ops : Symbol(Ops, Decl(genericFunctionsAndConditionalInference.ts, 18, 62))
135+
136+
const right: Ops<"right"> = {} as any
137+
>right : Symbol(right, Decl(genericFunctionsAndConditionalInference.ts, 28, 5))
138+
>Ops : Symbol(Ops, Decl(genericFunctionsAndConditionalInference.ts, 18, 62))
139+
140+
const ok = <F extends Target>(at: Ops<F>) => ({lr: at.lr(at.str, at.num)})
141+
>ok : Symbol(ok, Decl(genericFunctionsAndConditionalInference.ts, 30, 5))
142+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 30, 12))
143+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
144+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 30, 30))
145+
>Ops : Symbol(Ops, Decl(genericFunctionsAndConditionalInference.ts, 18, 62))
146+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 30, 12))
147+
>lr : Symbol(lr, Decl(genericFunctionsAndConditionalInference.ts, 30, 47))
148+
>at.lr : Symbol(Ops.lr, Decl(genericFunctionsAndConditionalInference.ts, 23, 26))
149+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 30, 30))
150+
>lr : Symbol(Ops.lr, Decl(genericFunctionsAndConditionalInference.ts, 23, 26))
151+
>at.str : Symbol(Ops.str, Decl(genericFunctionsAndConditionalInference.ts, 21, 9))
152+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 30, 30))
153+
>str : Symbol(Ops.str, Decl(genericFunctionsAndConditionalInference.ts, 21, 9))
154+
>at.num : Symbol(Ops.num, Decl(genericFunctionsAndConditionalInference.ts, 22, 26))
155+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 30, 30))
156+
>num : Symbol(Ops.num, Decl(genericFunctionsAndConditionalInference.ts, 22, 26))
157+
158+
const orphaned = <F extends Target>(at: Ops<F>) => at.dict(ok(at))
159+
>orphaned : Symbol(orphaned, Decl(genericFunctionsAndConditionalInference.ts, 31, 5))
160+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 31, 18))
161+
>Target : Symbol(Target, Decl(genericFunctionsAndConditionalInference.ts, 14, 1))
162+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 31, 36))
163+
>Ops : Symbol(Ops, Decl(genericFunctionsAndConditionalInference.ts, 18, 62))
164+
>F : Symbol(F, Decl(genericFunctionsAndConditionalInference.ts, 31, 18))
165+
>at.dict : Symbol(Ops.dict, Decl(genericFunctionsAndConditionalInference.ts, 24, 70))
166+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 31, 36))
167+
>dict : Symbol(Ops.dict, Decl(genericFunctionsAndConditionalInference.ts, 24, 70))
168+
>ok : Symbol(ok, Decl(genericFunctionsAndConditionalInference.ts, 30, 5))
169+
>at : Symbol(at, Decl(genericFunctionsAndConditionalInference.ts, 31, 36))
170+
171+
const leftOk = ok(left)
172+
>leftOk : Symbol(leftOk, Decl(genericFunctionsAndConditionalInference.ts, 33, 5))
173+
>ok : Symbol(ok, Decl(genericFunctionsAndConditionalInference.ts, 30, 5))
174+
>left : Symbol(left, Decl(genericFunctionsAndConditionalInference.ts, 27, 5))
175+
176+
const leftOrphaned = orphaned(left)
177+
>leftOrphaned : Symbol(leftOrphaned, Decl(genericFunctionsAndConditionalInference.ts, 34, 5))
178+
>orphaned : Symbol(orphaned, Decl(genericFunctionsAndConditionalInference.ts, 31, 5))
179+
>left : Symbol(left, Decl(genericFunctionsAndConditionalInference.ts, 27, 5))
180+
181+
const rightOk = ok(right)
182+
>rightOk : Symbol(rightOk, Decl(genericFunctionsAndConditionalInference.ts, 36, 5))
183+
>ok : Symbol(ok, Decl(genericFunctionsAndConditionalInference.ts, 30, 5))
184+
>right : Symbol(right, Decl(genericFunctionsAndConditionalInference.ts, 28, 5))
185+
186+
const rightOrphaned = orphaned(right)
187+
>rightOrphaned : Symbol(rightOrphaned, Decl(genericFunctionsAndConditionalInference.ts, 37, 5))
188+
>orphaned : Symbol(orphaned, Decl(genericFunctionsAndConditionalInference.ts, 31, 5))
189+
>right : Symbol(right, Decl(genericFunctionsAndConditionalInference.ts, 28, 5))
190+

0 commit comments

Comments
 (0)