Skip to content

Commit d1f87d1

Browse files
authored
Support partial reverse mapped inferences with tuple types (microsoft#41106)
* Support partial reverse mapped inferences with tuple types * Add tests * Accept new baselines
1 parent 97083ea commit d1f87d1

File tree

6 files changed

+304
-1
lines changed

6 files changed

+304
-1
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19709,7 +19709,8 @@ namespace ts {
1970919709
// arrow function, but is considered partially inferable because property 'a' has an inferable type.
1971019710
function isPartiallyInferableType(type: Type): boolean {
1971119711
return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) ||
19712-
isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop)));
19712+
isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) ||
19713+
isTupleType(type) && some(getTypeArguments(type), isPartiallyInferableType);
1971319714
}
1971419715

1971519716
function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) {

tests/baselines/reference/reverseMappedPartiallyInferableTypes.errors.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,36 @@ tests/cases/compiler/reverseMappedPartiallyInferableTypes.ts(91,20): error TS257
9898
}
9999
}
100100
});
101+
102+
// Repros from #40809
103+
104+
type Mapped1<T> = {
105+
[K in keyof T]: [T[K], (arg: T) => boolean];
106+
};
107+
108+
declare function inferMapped1<T>(arg: Mapped1<T>): void;
109+
110+
inferMapped1({
111+
key: [3, arg => arg.key > 5]
112+
});
113+
114+
type Mapped2<T> = {
115+
[K in keyof T]: [T[K], unknown extends T ? unknown : (arg: T) => boolean];
116+
};
117+
118+
declare function inferMapped2<T>(arg: Mapped2<T>): void;
119+
120+
inferMapped2({
121+
key: [3, arg => arg.key > 5]
122+
});
123+
124+
type MappedReadonly<T> = {
125+
readonly [K in keyof T]: readonly [T[K], (arg: T) => boolean];
126+
};
127+
128+
declare function inferMappedReadonly<T>(arg: MappedReadonly<T>): void;
129+
130+
inferMappedReadonly({
131+
key: [3, arg => arg.key > 5]
132+
});
101133

tests/baselines/reference/reverseMappedPartiallyInferableTypes.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,38 @@ const obj3 = id({
9393
}
9494
}
9595
});
96+
97+
// Repros from #40809
98+
99+
type Mapped1<T> = {
100+
[K in keyof T]: [T[K], (arg: T) => boolean];
101+
};
102+
103+
declare function inferMapped1<T>(arg: Mapped1<T>): void;
104+
105+
inferMapped1({
106+
key: [3, arg => arg.key > 5]
107+
});
108+
109+
type Mapped2<T> = {
110+
[K in keyof T]: [T[K], unknown extends T ? unknown : (arg: T) => boolean];
111+
};
112+
113+
declare function inferMapped2<T>(arg: Mapped2<T>): void;
114+
115+
inferMapped2({
116+
key: [3, arg => arg.key > 5]
117+
});
118+
119+
type MappedReadonly<T> = {
120+
readonly [K in keyof T]: readonly [T[K], (arg: T) => boolean];
121+
};
122+
123+
declare function inferMappedReadonly<T>(arg: MappedReadonly<T>): void;
124+
125+
inferMappedReadonly({
126+
key: [3, arg => arg.key > 5]
127+
});
96128

97129

98130
//// [reverseMappedPartiallyInferableTypes.js]
@@ -142,3 +174,12 @@ var obj3 = id({
142174
}
143175
}
144176
});
177+
inferMapped1({
178+
key: [3, function (arg) { return arg.key > 5; }]
179+
});
180+
inferMapped2({
181+
key: [3, function (arg) { return arg.key > 5; }]
182+
});
183+
inferMappedReadonly({
184+
key: [3, function (arg) { return arg.key > 5; }]
185+
});

tests/baselines/reference/reverseMappedPartiallyInferableTypes.symbols

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,105 @@ const obj3 = id({
257257
}
258258
});
259259

260+
// Repros from #40809
261+
262+
type Mapped1<T> = {
263+
>Mapped1 : Symbol(Mapped1, Decl(reverseMappedPartiallyInferableTypes.ts, 93, 3))
264+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 97, 13))
265+
266+
[K in keyof T]: [T[K], (arg: T) => boolean];
267+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 98, 5))
268+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 97, 13))
269+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 97, 13))
270+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 98, 5))
271+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 98, 28))
272+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 97, 13))
273+
274+
};
275+
276+
declare function inferMapped1<T>(arg: Mapped1<T>): void;
277+
>inferMapped1 : Symbol(inferMapped1, Decl(reverseMappedPartiallyInferableTypes.ts, 99, 2))
278+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 101, 30))
279+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 101, 33))
280+
>Mapped1 : Symbol(Mapped1, Decl(reverseMappedPartiallyInferableTypes.ts, 93, 3))
281+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 101, 30))
282+
283+
inferMapped1({
284+
>inferMapped1 : Symbol(inferMapped1, Decl(reverseMappedPartiallyInferableTypes.ts, 99, 2))
285+
286+
key: [3, arg => arg.key > 5]
287+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 103, 14))
288+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 104, 12))
289+
>arg.key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 103, 14))
290+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 104, 12))
291+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 103, 14))
292+
293+
});
294+
295+
type Mapped2<T> = {
296+
>Mapped2 : Symbol(Mapped2, Decl(reverseMappedPartiallyInferableTypes.ts, 105, 3))
297+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 107, 13))
298+
299+
[K in keyof T]: [T[K], unknown extends T ? unknown : (arg: T) => boolean];
300+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 108, 5))
301+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 107, 13))
302+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 107, 13))
303+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 108, 5))
304+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 107, 13))
305+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 108, 58))
306+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 107, 13))
307+
308+
};
309+
310+
declare function inferMapped2<T>(arg: Mapped2<T>): void;
311+
>inferMapped2 : Symbol(inferMapped2, Decl(reverseMappedPartiallyInferableTypes.ts, 109, 2))
312+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 111, 30))
313+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 111, 33))
314+
>Mapped2 : Symbol(Mapped2, Decl(reverseMappedPartiallyInferableTypes.ts, 105, 3))
315+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 111, 30))
316+
317+
inferMapped2({
318+
>inferMapped2 : Symbol(inferMapped2, Decl(reverseMappedPartiallyInferableTypes.ts, 109, 2))
319+
320+
key: [3, arg => arg.key > 5]
321+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 113, 14))
322+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 114, 12))
323+
>arg.key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 113, 14))
324+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 114, 12))
325+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 113, 14))
326+
327+
});
328+
329+
type MappedReadonly<T> = {
330+
>MappedReadonly : Symbol(MappedReadonly, Decl(reverseMappedPartiallyInferableTypes.ts, 115, 3))
331+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 117, 20))
332+
333+
readonly [K in keyof T]: readonly [T[K], (arg: T) => boolean];
334+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 118, 14))
335+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 117, 20))
336+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 117, 20))
337+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes.ts, 118, 14))
338+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 118, 46))
339+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 117, 20))
340+
341+
};
342+
343+
declare function inferMappedReadonly<T>(arg: MappedReadonly<T>): void;
344+
>inferMappedReadonly : Symbol(inferMappedReadonly, Decl(reverseMappedPartiallyInferableTypes.ts, 119, 2))
345+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 121, 37))
346+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 121, 40))
347+
>MappedReadonly : Symbol(MappedReadonly, Decl(reverseMappedPartiallyInferableTypes.ts, 115, 3))
348+
>T : Symbol(T, Decl(reverseMappedPartiallyInferableTypes.ts, 121, 37))
349+
350+
inferMappedReadonly({
351+
>inferMappedReadonly : Symbol(inferMappedReadonly, Decl(reverseMappedPartiallyInferableTypes.ts, 119, 2))
352+
353+
key: [3, arg => arg.key > 5]
354+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 123, 21))
355+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 124, 12))
356+
>arg.key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 123, 21))
357+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes.ts, 124, 12))
358+
>key : Symbol(key, Decl(reverseMappedPartiallyInferableTypes.ts, 123, 21))
359+
360+
});
361+

tests/baselines/reference/reverseMappedPartiallyInferableTypes.types

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,98 @@ const obj3 = id({
229229
}
230230
});
231231

232+
// Repros from #40809
233+
234+
type Mapped1<T> = {
235+
>Mapped1 : Mapped1<T>
236+
237+
[K in keyof T]: [T[K], (arg: T) => boolean];
238+
>arg : T
239+
240+
};
241+
242+
declare function inferMapped1<T>(arg: Mapped1<T>): void;
243+
>inferMapped1 : <T>(arg: Mapped1<T>) => void
244+
>arg : Mapped1<T>
245+
246+
inferMapped1({
247+
>inferMapped1({ key: [3, arg => arg.key > 5]}) : void
248+
>inferMapped1 : <T>(arg: Mapped1<T>) => void
249+
>{ key: [3, arg => arg.key > 5]} : { key: [number, (arg: { key: number; }) => boolean]; }
250+
251+
key: [3, arg => arg.key > 5]
252+
>key : [number, (arg: { key: number; }) => boolean]
253+
>[3, arg => arg.key > 5] : [number, (arg: { key: number; }) => boolean]
254+
>3 : 3
255+
>arg => arg.key > 5 : (arg: { key: number; }) => boolean
256+
>arg : { key: number; }
257+
>arg.key > 5 : boolean
258+
>arg.key : number
259+
>arg : { key: number; }
260+
>key : number
261+
>5 : 5
262+
263+
});
264+
265+
type Mapped2<T> = {
266+
>Mapped2 : Mapped2<T>
267+
268+
[K in keyof T]: [T[K], unknown extends T ? unknown : (arg: T) => boolean];
269+
>arg : T
270+
271+
};
272+
273+
declare function inferMapped2<T>(arg: Mapped2<T>): void;
274+
>inferMapped2 : <T>(arg: Mapped2<T>) => void
275+
>arg : Mapped2<T>
276+
277+
inferMapped2({
278+
>inferMapped2({ key: [3, arg => arg.key > 5]}) : void
279+
>inferMapped2 : <T>(arg: Mapped2<T>) => void
280+
>{ key: [3, arg => arg.key > 5]} : { key: [number, (arg: { key: number; }) => boolean]; }
281+
282+
key: [3, arg => arg.key > 5]
283+
>key : [number, (arg: { key: number; }) => boolean]
284+
>[3, arg => arg.key > 5] : [number, (arg: { key: number; }) => boolean]
285+
>3 : 3
286+
>arg => arg.key > 5 : (arg: { key: number; }) => boolean
287+
>arg : { key: number; }
288+
>arg.key > 5 : boolean
289+
>arg.key : number
290+
>arg : { key: number; }
291+
>key : number
292+
>5 : 5
293+
294+
});
295+
296+
type MappedReadonly<T> = {
297+
>MappedReadonly : MappedReadonly<T>
298+
299+
readonly [K in keyof T]: readonly [T[K], (arg: T) => boolean];
300+
>arg : T
301+
302+
};
303+
304+
declare function inferMappedReadonly<T>(arg: MappedReadonly<T>): void;
305+
>inferMappedReadonly : <T>(arg: MappedReadonly<T>) => void
306+
>arg : MappedReadonly<T>
307+
308+
inferMappedReadonly({
309+
>inferMappedReadonly({ key: [3, arg => arg.key > 5]}) : void
310+
>inferMappedReadonly : <T>(arg: MappedReadonly<T>) => void
311+
>{ key: [3, arg => arg.key > 5]} : { key: [number, (arg: { key: number; }) => boolean]; }
312+
313+
key: [3, arg => arg.key > 5]
314+
>key : [number, (arg: { key: number; }) => boolean]
315+
>[3, arg => arg.key > 5] : [number, (arg: { key: number; }) => boolean]
316+
>3 : 3
317+
>arg => arg.key > 5 : (arg: { key: number; }) => boolean
318+
>arg : { key: number; }
319+
>arg.key > 5 : boolean
320+
>arg.key : number
321+
>arg : { key: number; }
322+
>key : number
323+
>5 : 5
324+
325+
});
326+

tests/cases/compiler/reverseMappedPartiallyInferableTypes.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,35 @@ const obj3 = id({
9494
}
9595
}
9696
});
97+
98+
// Repros from #40809
99+
100+
type Mapped1<T> = {
101+
[K in keyof T]: [T[K], (arg: T) => boolean];
102+
};
103+
104+
declare function inferMapped1<T>(arg: Mapped1<T>): void;
105+
106+
inferMapped1({
107+
key: [3, arg => arg.key > 5]
108+
});
109+
110+
type Mapped2<T> = {
111+
[K in keyof T]: [T[K], unknown extends T ? unknown : (arg: T) => boolean];
112+
};
113+
114+
declare function inferMapped2<T>(arg: Mapped2<T>): void;
115+
116+
inferMapped2({
117+
key: [3, arg => arg.key > 5]
118+
});
119+
120+
type MappedReadonly<T> = {
121+
readonly [K in keyof T]: readonly [T[K], (arg: T) => boolean];
122+
};
123+
124+
declare function inferMappedReadonly<T>(arg: MappedReadonly<T>): void;
125+
126+
inferMappedReadonly({
127+
key: [3, arg => arg.key > 5]
128+
});

0 commit comments

Comments
 (0)