Skip to content

Commit 9e6c3e1

Browse files
committed
Infer intersected reverse mapped types
1 parent 747172e commit 9e6c3e1

File tree

4 files changed

+538
-8
lines changed

4 files changed

+538
-8
lines changed

src/compiler/checker.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -15688,7 +15688,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1568815688
const type = elementTypes[i];
1568915689
const flags = target.elementFlags[i];
1569015690
if (flags & ElementFlags.Variadic) {
15691-
if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
15691+
if (type.flags & TypeFlags.InstantiableNonPrimitive || everyContainedType(type, isGenericMappedType)) {
1569215692
// Generic variadic elements stay as they are.
1569315693
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
1569415694
}
@@ -28416,13 +28416,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2841628416

2841728417
function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) {
2841828418
return mapType(type, t => {
28419-
if (isGenericMappedType(t) && !t.declaration.nameType) {
28420-
const constraint = getConstraintTypeFromMappedType(t);
28421-
const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
28422-
const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
28423-
if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
28424-
return substituteIndexedMappedType(t, propertyNameType);
28425-
}
28419+
if (everyContainedType(t, t => isGenericMappedType(t) && !t.declaration.nameType)) {
28420+
const newTypes = mapDefined(t.flags & TypeFlags.Intersection ? (t as IntersectionType).types : [t], t => {
28421+
const mappedType = t as MappedType;
28422+
const constraint = getConstraintTypeFromMappedType(mappedType);
28423+
const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
28424+
const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
28425+
if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
28426+
return substituteIndexedMappedType(mappedType, propertyNameType);
28427+
}
28428+
});
28429+
return newTypes.length ? getIntersectionType(newTypes) : undefined;
2842628430
}
2842728431
else if (t.flags & TypeFlags.StructuredType) {
2842828432
const prop = getPropertyOfType(t, name);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
=== tests/cases/compiler/reverseMappedIntersectionInference.ts ===
2+
type ResultsKeyed<T> = {
3+
>ResultsKeyed : Symbol(ResultsKeyed, Decl(reverseMappedIntersectionInference.ts, 0, 0))
4+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 18))
5+
6+
[K in keyof T]: {
7+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
8+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 18))
9+
10+
data: T[K];
11+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 1, 19))
12+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 18))
13+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
14+
15+
onSuccess: (data: T[K]) => void;
16+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 2, 15))
17+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 3, 16))
18+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 18))
19+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
20+
21+
};
22+
};
23+
24+
type ErrorsKeyed<E> = {
25+
>ErrorsKeyed : Symbol(ErrorsKeyed, Decl(reverseMappedIntersectionInference.ts, 5, 2))
26+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 17))
27+
28+
[K in keyof E]: {
29+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))
30+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 17))
31+
32+
error: E[K];
33+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 8, 19))
34+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 17))
35+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))
36+
37+
onError: (data: E[K]) => void;
38+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 9, 16))
39+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 10, 14))
40+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 17))
41+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))
42+
43+
};
44+
};
45+
46+
declare function withKeyedObj<T, E>(
47+
>withKeyedObj : Symbol(withKeyedObj, Decl(reverseMappedIntersectionInference.ts, 12, 2))
48+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
49+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))
50+
51+
arg: ResultsKeyed<T> & ErrorsTuple<E>
52+
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 14, 36))
53+
>ResultsKeyed : Symbol(ResultsKeyed, Decl(reverseMappedIntersectionInference.ts, 0, 0))
54+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
55+
>ErrorsTuple : Symbol(ErrorsTuple, Decl(reverseMappedIntersectionInference.ts, 46, 2))
56+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))
57+
58+
): [T, E];
59+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
60+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))
61+
62+
const res = withKeyedObj({
63+
>res : Symbol(res, Decl(reverseMappedIntersectionInference.ts, 18, 5))
64+
>withKeyedObj : Symbol(withKeyedObj, Decl(reverseMappedIntersectionInference.ts, 12, 2))
65+
66+
a: {
67+
>a : Symbol(a, Decl(reverseMappedIntersectionInference.ts, 18, 26))
68+
69+
data: "foo",
70+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 19, 6))
71+
72+
onSuccess: (dataArg) => {
73+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 20, 16))
74+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 21, 16))
75+
76+
dataArg;
77+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 21, 16))
78+
79+
},
80+
error: 404,
81+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 23, 6))
82+
83+
onError: (errorArg) => {
84+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 24, 15))
85+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 25, 14))
86+
87+
errorArg;
88+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 25, 14))
89+
90+
},
91+
},
92+
b: {
93+
>b : Symbol(b, Decl(reverseMappedIntersectionInference.ts, 28, 4))
94+
95+
data: true,
96+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 29, 6))
97+
98+
onSuccess: (dataArg) => {
99+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 30, 15))
100+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 31, 16))
101+
102+
dataArg;
103+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 31, 16))
104+
105+
},
106+
error: 500,
107+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 33, 6))
108+
109+
onError: (errorArg) => {
110+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 34, 15))
111+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 35, 14))
112+
113+
errorArg;
114+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 35, 14))
115+
116+
},
117+
},
118+
});
119+
120+
type ResultsTuple<T> = {
121+
>ResultsTuple : Symbol(ResultsTuple, Decl(reverseMappedIntersectionInference.ts, 39, 3))
122+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 18))
123+
124+
[K in keyof T]: {
125+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 42, 3))
126+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 18))
127+
128+
data: T[K];
129+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 42, 19))
130+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 18))
131+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 42, 3))
132+
133+
onSuccess: (data: T[K]) => void;
134+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 43, 15))
135+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 44, 16))
136+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 18))
137+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 42, 3))
138+
139+
};
140+
};
141+
142+
type ErrorsTuple<E> = {
143+
>ErrorsTuple : Symbol(ErrorsTuple, Decl(reverseMappedIntersectionInference.ts, 46, 2))
144+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 48, 17))
145+
146+
[K in keyof E]: {
147+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 49, 3))
148+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 48, 17))
149+
150+
error: E[K];
151+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 49, 19))
152+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 48, 17))
153+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 49, 3))
154+
155+
onError: (data: E[K]) => void;
156+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 50, 16))
157+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 51, 14))
158+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 48, 17))
159+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 49, 3))
160+
161+
};
162+
};
163+
164+
declare function withTuples<T extends any[], E extends any[]>(
165+
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 53, 2))
166+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 55, 28))
167+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 55, 44))
168+
169+
arg: [...(ResultsTuple<T> & ErrorsTuple<E>)]
170+
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 55, 62))
171+
>ResultsTuple : Symbol(ResultsTuple, Decl(reverseMappedIntersectionInference.ts, 39, 3))
172+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 55, 28))
173+
>ErrorsTuple : Symbol(ErrorsTuple, Decl(reverseMappedIntersectionInference.ts, 46, 2))
174+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 55, 44))
175+
176+
): [T, E];
177+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 55, 28))
178+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 55, 44))
179+
180+
const res2 = withTuples([
181+
>res2 : Symbol(res2, Decl(reverseMappedIntersectionInference.ts, 59, 5))
182+
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 53, 2))
183+
{
184+
data: "foo",
185+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 60, 3))
186+
187+
onSuccess: (dataArg) => {
188+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 61, 16))
189+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 62, 16))
190+
191+
dataArg;
192+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 62, 16))
193+
194+
},
195+
error: 404,
196+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 64, 6))
197+
198+
onError: (errorArg) => {
199+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 65, 15))
200+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 66, 14))
201+
202+
errorArg;
203+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 66, 14))
204+
205+
},
206+
},
207+
{
208+
data: true,
209+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 70, 3))
210+
211+
onSuccess: (dataArg) => {
212+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 71, 15))
213+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 72, 16))
214+
215+
dataArg;
216+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 72, 16))
217+
218+
},
219+
error: 500,
220+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 74, 6))
221+
222+
onError: (errorArg) => {
223+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 75, 15))
224+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 76, 14))
225+
226+
errorArg;
227+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 76, 14))
228+
229+
},
230+
},
231+
]);
232+

0 commit comments

Comments
 (0)