Skip to content

Commit ef2fba1

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

File tree

4 files changed

+452
-8
lines changed

4 files changed

+452
-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,188 @@
1+
=== tests/cases/compiler/reverseMappedIntersectionInference.ts ===
2+
type Results<T> = {
3+
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
4+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))
5+
6+
[K in keyof T]: {
7+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
8+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))
9+
10+
data: T[K];
11+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 1, 19))
12+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))
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, 13))
19+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
20+
21+
};
22+
};
23+
24+
type Errors<E> = {
25+
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
26+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))
27+
28+
[K in keyof E]: {
29+
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))
30+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))
31+
32+
error: E[K];
33+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 8, 19))
34+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))
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, 12))
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: Results<T> & Errors<E>
52+
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 14, 36))
53+
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
54+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
55+
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 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+
declare function withTuples<T extends any[], E extends any[]>(
121+
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 39, 3))
122+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
123+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))
124+
125+
arg: [...(Results<T> & Errors<E>)]
126+
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 41, 62))
127+
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
128+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
129+
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
130+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))
131+
132+
): [T, E];
133+
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
134+
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))
135+
136+
const res2 = withTuples([
137+
>res2 : Symbol(res2, Decl(reverseMappedIntersectionInference.ts, 45, 5))
138+
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 39, 3))
139+
{
140+
data: "foo",
141+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 46, 3))
142+
143+
onSuccess: (dataArg) => {
144+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 47, 16))
145+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 48, 16))
146+
147+
dataArg;
148+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 48, 16))
149+
150+
},
151+
error: 404,
152+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 50, 6))
153+
154+
onError: (errorArg) => {
155+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 51, 15))
156+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 52, 14))
157+
158+
errorArg;
159+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 52, 14))
160+
161+
},
162+
},
163+
{
164+
data: true,
165+
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 56, 3))
166+
167+
onSuccess: (dataArg) => {
168+
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 57, 15))
169+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 58, 16))
170+
171+
dataArg;
172+
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 58, 16))
173+
174+
},
175+
error: 500,
176+
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 60, 6))
177+
178+
onError: (errorArg) => {
179+
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 61, 15))
180+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 62, 14))
181+
182+
errorArg;
183+
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 62, 14))
184+
185+
},
186+
},
187+
]);
188+

0 commit comments

Comments
 (0)