Skip to content

Commit bdcc240

Browse files
authoredOct 13, 2022
Remove bug-causing carve-out in conditional type instantiation that hopefully is no longer required (#51151)
1 parent 37317a2 commit bdcc240

5 files changed

+246
-5
lines changed
 

‎src/compiler/checker.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -16372,11 +16372,7 @@ namespace ts {
1637216372
}
1637316373
}
1637416374
}
16375-
// We skip inference of the possible `infer` types unles the `extendsType` _is_ an infer type
16376-
// if it was, it's trivial to say that extendsType = checkType, however such a pattern is used to
16377-
// "reset" the type being build up during constraint calculation and avoid making an apparently "infinite" constraint
16378-
// so in those cases we refain from performing inference and retain the uninfered type parameter
16379-
if (!checkTypeInstantiable || !some(root.inferTypeParameters, t => t === extendsType)) {
16375+
if (!checkTypeInstantiable) {
1638016376
// We don't want inferences from constraints as they may cause us to eagerly resolve the
1638116377
// conditional type instead of deferring resolution. Also, we always want strict function
1638216378
// types rules (i.e. proper contravariance) for inferences.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//// [recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts]
2+
export {}
3+
export interface Option<T> {
4+
zip1<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray1<O>]>;
5+
6+
zip2<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray2<O>]>;
7+
8+
zip3<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray3<O>]>;
9+
}
10+
11+
type UnzipOption<T> = T extends Option<infer V> ? V : never;
12+
13+
/// This doesn't work
14+
type UnzipOptionArray1<T> = { [k in keyof T]: T[k] extends Option<any> ? UnzipOption<T[k]> : never };
15+
16+
/// But these work
17+
type UnzipOptionArray2<T> = { [k in keyof T]: UnzipOption<T[k]> };
18+
type UnzipOptionArray3<T> = { [k in keyof T]: T[k] extends Option<infer V> ? V : never };
19+
20+
declare const opt1: Option<number>;
21+
declare const opt2: Option<string>;
22+
declare const opt3: Option<boolean>;
23+
24+
const zipped1 = opt1.zip1(opt2, opt3);
25+
const zipped2 = opt1.zip2(opt2, opt3);
26+
const zipped3 = opt1.zip3(opt2, opt3);
27+
28+
//// [recursiveTypeAliasWithSpreadConditionalReturnNotCircular.js]
29+
"use strict";
30+
exports.__esModule = true;
31+
var zipped1 = opt1.zip1(opt2, opt3);
32+
var zipped2 = opt1.zip2(opt2, opt3);
33+
var zipped3 = opt1.zip3(opt2, opt3);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
=== tests/cases/compiler/recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts ===
2+
export {}
3+
export interface Option<T> {
4+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
5+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 24))
6+
7+
zip1<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray1<O>]>;
8+
>zip1 : Symbol(Option.zip1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 28))
9+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 6))
10+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
11+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
12+
>others : Symbol(others, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 36))
13+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 6))
14+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
15+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 24))
16+
>UnzipOptionArray1 : Symbol(UnzipOptionArray1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 60))
17+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 6))
18+
19+
zip2<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray2<O>]>;
20+
>zip2 : Symbol(Option.zip2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 88))
21+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 6))
22+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
23+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
24+
>others : Symbol(others, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 36))
25+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 6))
26+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
27+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 24))
28+
>UnzipOptionArray2 : Symbol(UnzipOptionArray2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 101))
29+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 6))
30+
31+
zip3<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray3<O>]>;
32+
>zip3 : Symbol(Option.zip3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 88))
33+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 6, 6))
34+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
35+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
36+
>others : Symbol(others, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 6, 36))
37+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 6, 6))
38+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
39+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 24))
40+
>UnzipOptionArray3 : Symbol(UnzipOptionArray3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 66))
41+
>O : Symbol(O, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 6, 6))
42+
}
43+
44+
type UnzipOption<T> = T extends Option<infer V> ? V : never;
45+
>UnzipOption : Symbol(UnzipOption, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 7, 1))
46+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 17))
47+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 17))
48+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
49+
>V : Symbol(V, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 44))
50+
>V : Symbol(V, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 44))
51+
52+
/// This doesn't work
53+
type UnzipOptionArray1<T> = { [k in keyof T]: T[k] extends Option<any> ? UnzipOption<T[k]> : never };
54+
>UnzipOptionArray1 : Symbol(UnzipOptionArray1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 9, 60))
55+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 23))
56+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 31))
57+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 23))
58+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 23))
59+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 31))
60+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
61+
>UnzipOption : Symbol(UnzipOption, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 7, 1))
62+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 23))
63+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 31))
64+
65+
/// But these work
66+
type UnzipOptionArray2<T> = { [k in keyof T]: UnzipOption<T[k]> };
67+
>UnzipOptionArray2 : Symbol(UnzipOptionArray2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 12, 101))
68+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 23))
69+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 31))
70+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 23))
71+
>UnzipOption : Symbol(UnzipOption, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 7, 1))
72+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 23))
73+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 31))
74+
75+
type UnzipOptionArray3<T> = { [k in keyof T]: T[k] extends Option<infer V> ? V : never };
76+
>UnzipOptionArray3 : Symbol(UnzipOptionArray3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 15, 66))
77+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 23))
78+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 31))
79+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 23))
80+
>T : Symbol(T, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 23))
81+
>k : Symbol(k, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 31))
82+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
83+
>V : Symbol(V, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 71))
84+
>V : Symbol(V, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 16, 71))
85+
86+
declare const opt1: Option<number>;
87+
>opt1 : Symbol(opt1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 18, 13))
88+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
89+
90+
declare const opt2: Option<string>;
91+
>opt2 : Symbol(opt2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 19, 13))
92+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
93+
94+
declare const opt3: Option<boolean>;
95+
>opt3 : Symbol(opt3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 20, 13))
96+
>Option : Symbol(Option, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 0, 9))
97+
98+
const zipped1 = opt1.zip1(opt2, opt3);
99+
>zipped1 : Symbol(zipped1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 22, 5))
100+
>opt1.zip1 : Symbol(Option.zip1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 28))
101+
>opt1 : Symbol(opt1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 18, 13))
102+
>zip1 : Symbol(Option.zip1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 1, 28))
103+
>opt2 : Symbol(opt2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 19, 13))
104+
>opt3 : Symbol(opt3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 20, 13))
105+
106+
const zipped2 = opt1.zip2(opt2, opt3);
107+
>zipped2 : Symbol(zipped2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 23, 5))
108+
>opt1.zip2 : Symbol(Option.zip2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 88))
109+
>opt1 : Symbol(opt1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 18, 13))
110+
>zip2 : Symbol(Option.zip2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 2, 88))
111+
>opt2 : Symbol(opt2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 19, 13))
112+
>opt3 : Symbol(opt3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 20, 13))
113+
114+
const zipped3 = opt1.zip3(opt2, opt3);
115+
>zipped3 : Symbol(zipped3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 24, 5))
116+
>opt1.zip3 : Symbol(Option.zip3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 88))
117+
>opt1 : Symbol(opt1, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 18, 13))
118+
>zip3 : Symbol(Option.zip3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 4, 88))
119+
>opt2 : Symbol(opt2, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 19, 13))
120+
>opt3 : Symbol(opt3, Decl(recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts, 20, 13))
121+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
=== tests/cases/compiler/recursiveTypeAliasWithSpreadConditionalReturnNotCircular.ts ===
2+
export {}
3+
export interface Option<T> {
4+
zip1<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray1<O>]>;
5+
>zip1 : <O extends Option<any>[]>(...others: O) => Option<[T, ...UnzipOptionArray1<O>]>
6+
>others : O
7+
8+
zip2<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray2<O>]>;
9+
>zip2 : <O extends Option<any>[]>(...others: O) => Option<[T, ...UnzipOptionArray2<O>]>
10+
>others : O
11+
12+
zip3<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray3<O>]>;
13+
>zip3 : <O extends Option<any>[]>(...others: O) => Option<[T, ...UnzipOptionArray3<O>]>
14+
>others : O
15+
}
16+
17+
type UnzipOption<T> = T extends Option<infer V> ? V : never;
18+
>UnzipOption : UnzipOption<T>
19+
20+
/// This doesn't work
21+
type UnzipOptionArray1<T> = { [k in keyof T]: T[k] extends Option<any> ? UnzipOption<T[k]> : never };
22+
>UnzipOptionArray1 : UnzipOptionArray1<T>
23+
24+
/// But these work
25+
type UnzipOptionArray2<T> = { [k in keyof T]: UnzipOption<T[k]> };
26+
>UnzipOptionArray2 : UnzipOptionArray2<T>
27+
28+
type UnzipOptionArray3<T> = { [k in keyof T]: T[k] extends Option<infer V> ? V : never };
29+
>UnzipOptionArray3 : UnzipOptionArray3<T>
30+
31+
declare const opt1: Option<number>;
32+
>opt1 : Option<number>
33+
34+
declare const opt2: Option<string>;
35+
>opt2 : Option<string>
36+
37+
declare const opt3: Option<boolean>;
38+
>opt3 : Option<boolean>
39+
40+
const zipped1 = opt1.zip1(opt2, opt3);
41+
>zipped1 : Option<[number, string, boolean]>
42+
>opt1.zip1(opt2, opt3) : Option<[number, string, boolean]>
43+
>opt1.zip1 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray1<O>]>
44+
>opt1 : Option<number>
45+
>zip1 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray1<O>]>
46+
>opt2 : Option<string>
47+
>opt3 : Option<boolean>
48+
49+
const zipped2 = opt1.zip2(opt2, opt3);
50+
>zipped2 : Option<[number, string, boolean]>
51+
>opt1.zip2(opt2, opt3) : Option<[number, string, boolean]>
52+
>opt1.zip2 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray2<O>]>
53+
>opt1 : Option<number>
54+
>zip2 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray2<O>]>
55+
>opt2 : Option<string>
56+
>opt3 : Option<boolean>
57+
58+
const zipped3 = opt1.zip3(opt2, opt3);
59+
>zipped3 : Option<[number, string, boolean]>
60+
>opt1.zip3(opt2, opt3) : Option<[number, string, boolean]>
61+
>opt1.zip3 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray3<O>]>
62+
>opt1 : Option<number>
63+
>zip3 : <O extends Option<any>[]>(...others: O) => Option<[number, ...UnzipOptionArray3<O>]>
64+
>opt2 : Option<string>
65+
>opt3 : Option<boolean>
66+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export {}
2+
export interface Option<T> {
3+
zip1<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray1<O>]>;
4+
5+
zip2<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray2<O>]>;
6+
7+
zip3<O extends Array<Option<any>>>(...others: O): Option<[T, ...UnzipOptionArray3<O>]>;
8+
}
9+
10+
type UnzipOption<T> = T extends Option<infer V> ? V : never;
11+
12+
/// This doesn't work
13+
type UnzipOptionArray1<T> = { [k in keyof T]: T[k] extends Option<any> ? UnzipOption<T[k]> : never };
14+
15+
/// But these work
16+
type UnzipOptionArray2<T> = { [k in keyof T]: UnzipOption<T[k]> };
17+
type UnzipOptionArray3<T> = { [k in keyof T]: T[k] extends Option<infer V> ? V : never };
18+
19+
declare const opt1: Option<number>;
20+
declare const opt2: Option<string>;
21+
declare const opt3: Option<boolean>;
22+
23+
const zipped1 = opt1.zip1(opt2, opt3);
24+
const zipped2 = opt1.zip2(opt2, opt3);
25+
const zipped3 = opt1.zip3(opt2, opt3);

0 commit comments

Comments
 (0)
Please sign in to comment.