Skip to content

Commit fefcb81

Browse files
authored
Add extra tests for recursive conditional types (#54030)
1 parent 1518cd9 commit fefcb81

File tree

3 files changed

+378
-0
lines changed

3 files changed

+378
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
=== tests/cases/compiler/recursiveConditionalTypes2.ts ===
2+
// repro from https://github.com/microsoft/TypeScript/issues/43877
3+
4+
type UnionToIntersection<U> = (
5+
>UnionToIntersection : Symbol(UnionToIntersection, Decl(recursiveConditionalTypes2.ts, 0, 0))
6+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 2, 25))
7+
8+
U extends any ? (k: U) => unknown : never
9+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 2, 25))
10+
>k : Symbol(k, Decl(recursiveConditionalTypes2.ts, 3, 19))
11+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 2, 25))
12+
13+
) extends (k: infer I) => unknown
14+
>k : Symbol(k, Decl(recursiveConditionalTypes2.ts, 4, 11))
15+
>I : Symbol(I, Decl(recursiveConditionalTypes2.ts, 4, 19))
16+
17+
? I
18+
>I : Symbol(I, Decl(recursiveConditionalTypes2.ts, 4, 19))
19+
20+
: never;
21+
22+
interface ClassSpec {
23+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
24+
25+
public?: object;
26+
>public : Symbol(ClassSpec.public, Decl(recursiveConditionalTypes2.ts, 8, 21))
27+
28+
private?: object;
29+
>private : Symbol(ClassSpec.private, Decl(recursiveConditionalTypes2.ts, 9, 18))
30+
31+
publicExtends?: Record<string, ClassSpec>;
32+
>publicExtends : Symbol(ClassSpec.publicExtends, Decl(recursiveConditionalTypes2.ts, 10, 19))
33+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
34+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
35+
36+
privateExtends?: Record<string, ClassSpec>;
37+
>privateExtends : Symbol(ClassSpec.privateExtends, Decl(recursiveConditionalTypes2.ts, 11, 44))
38+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
39+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
40+
}
41+
42+
type MaybeMergePrivateSuperSpec<T> = T extends Record<string, ClassSpec>
43+
>MaybeMergePrivateSuperSpec : Symbol(MaybeMergePrivateSuperSpec, Decl(recursiveConditionalTypes2.ts, 13, 1))
44+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 15, 32))
45+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 15, 32))
46+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
47+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
48+
49+
? MergePrivateSuperSpec<T>
50+
>MergePrivateSuperSpec : Symbol(MergePrivateSuperSpec, Decl(recursiveConditionalTypes2.ts, 26, 2))
51+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 15, 32))
52+
53+
: {};
54+
55+
type MaybeMergePrivateSpecs<T extends ClassSpec, U> = U extends ClassSpec
56+
>MaybeMergePrivateSpecs : Symbol(MaybeMergePrivateSpecs, Decl(recursiveConditionalTypes2.ts, 17, 7))
57+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 19, 28))
58+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
59+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 19, 48))
60+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 19, 48))
61+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
62+
63+
? MergePrivateSpecs<U, T>
64+
>MergePrivateSpecs : Symbol(MergePrivateSpecs, Decl(recursiveConditionalTypes2.ts, 21, 6))
65+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 19, 48))
66+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 19, 28))
67+
68+
: T;
69+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 19, 28))
70+
71+
type MergePrivateSpecs<T extends ClassSpec, U extends ClassSpec> = {
72+
>MergePrivateSpecs : Symbol(MergePrivateSpecs, Decl(recursiveConditionalTypes2.ts, 21, 6))
73+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 23, 23))
74+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
75+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 23, 43))
76+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
77+
78+
public: T["public"] & U["public"];
79+
>public : Symbol(public, Decl(recursiveConditionalTypes2.ts, 23, 68))
80+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 23, 23))
81+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 23, 43))
82+
83+
private: T["private"] & U["private"];
84+
>private : Symbol(private, Decl(recursiveConditionalTypes2.ts, 24, 36))
85+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 23, 23))
86+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 23, 43))
87+
88+
};
89+
90+
type MergePrivateSuperSpec<T extends Record<string, ClassSpec>> =
91+
>MergePrivateSuperSpec : Symbol(MergePrivateSuperSpec, Decl(recursiveConditionalTypes2.ts, 26, 2))
92+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 28, 27))
93+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
94+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
95+
96+
UnionToIntersection<
97+
>UnionToIntersection : Symbol(UnionToIntersection, Decl(recursiveConditionalTypes2.ts, 0, 0))
98+
{
99+
[P in keyof T]: SimplifyPrivateSpec<T[P]>;
100+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 31, 7))
101+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 28, 27))
102+
>SimplifyPrivateSpec : Symbol(SimplifyPrivateSpec, Decl(recursiveConditionalTypes2.ts, 33, 4))
103+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 28, 27))
104+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 31, 7))
105+
106+
}[keyof T]
107+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 28, 27))
108+
109+
>;
110+
111+
export type SimplifyPrivateSpec<T extends ClassSpec> = MaybeMergePrivateSpecs<
112+
>SimplifyPrivateSpec : Symbol(SimplifyPrivateSpec, Decl(recursiveConditionalTypes2.ts, 33, 4))
113+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 35, 32))
114+
>ClassSpec : Symbol(ClassSpec, Decl(recursiveConditionalTypes2.ts, 6, 10))
115+
>MaybeMergePrivateSpecs : Symbol(MaybeMergePrivateSpecs, Decl(recursiveConditionalTypes2.ts, 17, 7))
116+
117+
MaybeMergePrivateSpecs<T, MaybeMergePrivateSuperSpec<T["publicExtends"]>>,
118+
>MaybeMergePrivateSpecs : Symbol(MaybeMergePrivateSpecs, Decl(recursiveConditionalTypes2.ts, 17, 7))
119+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 35, 32))
120+
>MaybeMergePrivateSuperSpec : Symbol(MaybeMergePrivateSuperSpec, Decl(recursiveConditionalTypes2.ts, 13, 1))
121+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 35, 32))
122+
123+
MaybeMergePrivateSuperSpec<T["privateExtends"]>
124+
>MaybeMergePrivateSuperSpec : Symbol(MaybeMergePrivateSuperSpec, Decl(recursiveConditionalTypes2.ts, 13, 1))
125+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 35, 32))
126+
127+
>;
128+
129+
// repro from https://github.com/microsoft/TypeScript/issues/43877#issuecomment-866146516
130+
131+
type Converted<T> = {
132+
>Converted : Symbol(Converted, Decl(recursiveConditionalTypes2.ts, 38, 2))
133+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 42, 15))
134+
135+
[P in keyof T]: null extends T[P] ? T[P] : T[P];
136+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 43, 3))
137+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 42, 15))
138+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 42, 15))
139+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 43, 3))
140+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 42, 15))
141+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 43, 3))
142+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 42, 15))
143+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 43, 3))
144+
145+
};
146+
147+
type DefaultsDeep<T, U extends T> = {
148+
>DefaultsDeep : Symbol(DefaultsDeep, Decl(recursiveConditionalTypes2.ts, 44, 2))
149+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
150+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 46, 20))
151+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
152+
153+
[P in keyof T]-?: U[P] extends T[P]
154+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
155+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
156+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 46, 20))
157+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
158+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
159+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
160+
161+
? null extends U[P]
162+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 46, 20))
163+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
164+
165+
? Converted<DefaultsDeep<T[P], NonNullable<U[P]>>>
166+
>Converted : Symbol(Converted, Decl(recursiveConditionalTypes2.ts, 38, 2))
167+
>DefaultsDeep : Symbol(DefaultsDeep, Decl(recursiveConditionalTypes2.ts, 44, 2))
168+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
169+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
170+
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
171+
>U : Symbol(U, Decl(recursiveConditionalTypes2.ts, 46, 20))
172+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
173+
174+
: T[P]
175+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
176+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
177+
178+
: T[P];
179+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 46, 18))
180+
>P : Symbol(P, Decl(recursiveConditionalTypes2.ts, 47, 3))
181+
182+
};
183+
184+
interface _Array<T> {
185+
>_Array : Symbol(_Array, Decl(recursiveConditionalTypes2.ts, 52, 2))
186+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 54, 17))
187+
188+
find<S extends T>(predicate: (value: T) => boolean): void;
189+
>find : Symbol(_Array.find, Decl(recursiveConditionalTypes2.ts, 54, 21))
190+
>S : Symbol(S, Decl(recursiveConditionalTypes2.ts, 55, 7))
191+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 54, 17))
192+
>predicate : Symbol(predicate, Decl(recursiveConditionalTypes2.ts, 55, 20))
193+
>value : Symbol(value, Decl(recursiveConditionalTypes2.ts, 55, 32))
194+
>T : Symbol(T, Decl(recursiveConditionalTypes2.ts, 54, 17))
195+
}
196+
197+
const z: _Array<DefaultsDeep<{}, {}>> = [];
198+
>z : Symbol(z, Decl(recursiveConditionalTypes2.ts, 58, 5))
199+
>_Array : Symbol(_Array, Decl(recursiveConditionalTypes2.ts, 52, 2))
200+
>DefaultsDeep : Symbol(DefaultsDeep, Decl(recursiveConditionalTypes2.ts, 44, 2))
201+
202+
z.find((_) => true);
203+
>z.find : Symbol(_Array.find, Decl(recursiveConditionalTypes2.ts, 54, 21))
204+
>z : Symbol(z, Decl(recursiveConditionalTypes2.ts, 58, 5))
205+
>find : Symbol(_Array.find, Decl(recursiveConditionalTypes2.ts, 54, 21))
206+
>_ : Symbol(_, Decl(recursiveConditionalTypes2.ts, 60, 8))
207+
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
=== tests/cases/compiler/recursiveConditionalTypes2.ts ===
2+
// repro from https://github.com/microsoft/TypeScript/issues/43877
3+
4+
type UnionToIntersection<U> = (
5+
>UnionToIntersection : UnionToIntersection<U>
6+
7+
U extends any ? (k: U) => unknown : never
8+
>k : U
9+
10+
) extends (k: infer I) => unknown
11+
>k : I
12+
13+
? I
14+
: never;
15+
16+
interface ClassSpec {
17+
public?: object;
18+
>public : object | undefined
19+
20+
private?: object;
21+
>private : object | undefined
22+
23+
publicExtends?: Record<string, ClassSpec>;
24+
>publicExtends : Record<string, ClassSpec> | undefined
25+
26+
privateExtends?: Record<string, ClassSpec>;
27+
>privateExtends : Record<string, ClassSpec> | undefined
28+
}
29+
30+
type MaybeMergePrivateSuperSpec<T> = T extends Record<string, ClassSpec>
31+
>MaybeMergePrivateSuperSpec : MaybeMergePrivateSuperSpec<T>
32+
33+
? MergePrivateSuperSpec<T>
34+
: {};
35+
36+
type MaybeMergePrivateSpecs<T extends ClassSpec, U> = U extends ClassSpec
37+
>MaybeMergePrivateSpecs : MaybeMergePrivateSpecs<T, U>
38+
39+
? MergePrivateSpecs<U, T>
40+
: T;
41+
42+
type MergePrivateSpecs<T extends ClassSpec, U extends ClassSpec> = {
43+
>MergePrivateSpecs : MergePrivateSpecs<T, U>
44+
45+
public: T["public"] & U["public"];
46+
>public : T["public"] & U["public"]
47+
48+
private: T["private"] & U["private"];
49+
>private : T["private"] & U["private"]
50+
51+
};
52+
53+
type MergePrivateSuperSpec<T extends Record<string, ClassSpec>> =
54+
>MergePrivateSuperSpec : MergePrivateSuperSpec<T>
55+
56+
UnionToIntersection<
57+
{
58+
[P in keyof T]: SimplifyPrivateSpec<T[P]>;
59+
}[keyof T]
60+
>;
61+
62+
export type SimplifyPrivateSpec<T extends ClassSpec> = MaybeMergePrivateSpecs<
63+
>SimplifyPrivateSpec : SimplifyPrivateSpec<T>
64+
65+
MaybeMergePrivateSpecs<T, MaybeMergePrivateSuperSpec<T["publicExtends"]>>,
66+
MaybeMergePrivateSuperSpec<T["privateExtends"]>
67+
>;
68+
69+
// repro from https://github.com/microsoft/TypeScript/issues/43877#issuecomment-866146516
70+
71+
type Converted<T> = {
72+
>Converted : Converted<T>
73+
74+
[P in keyof T]: null extends T[P] ? T[P] : T[P];
75+
};
76+
77+
type DefaultsDeep<T, U extends T> = {
78+
>DefaultsDeep : DefaultsDeep<T, U>
79+
80+
[P in keyof T]-?: U[P] extends T[P]
81+
? null extends U[P]
82+
? Converted<DefaultsDeep<T[P], NonNullable<U[P]>>>
83+
: T[P]
84+
: T[P];
85+
};
86+
87+
interface _Array<T> {
88+
find<S extends T>(predicate: (value: T) => boolean): void;
89+
>find : <S extends T>(predicate: (value: T) => boolean) => void
90+
>predicate : (value: T) => boolean
91+
>value : T
92+
}
93+
94+
const z: _Array<DefaultsDeep<{}, {}>> = [];
95+
>z : _Array<DefaultsDeep<{}, {}>>
96+
>[] : never[]
97+
98+
z.find((_) => true);
99+
>z.find((_) => true) : void
100+
>z.find : <S extends DefaultsDeep<{}, {}>>(predicate: (value: DefaultsDeep<{}, {}>) => boolean) => void
101+
>z : _Array<DefaultsDeep<{}, {}>>
102+
>find : <S extends DefaultsDeep<{}, {}>>(predicate: (value: DefaultsDeep<{}, {}>) => boolean) => void
103+
>(_) => true : (_: DefaultsDeep<{}, {}>) => true
104+
>_ : DefaultsDeep<{}, {}>
105+
>true : true
106+

Diff for: tests/cases/compiler/recursiveConditionalTypes2.ts

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// @strict: true
2+
// @lib: esnext
3+
// @noEmit: true
4+
5+
// repro from https://github.com/microsoft/TypeScript/issues/43877
6+
7+
type UnionToIntersection<U> = (
8+
U extends any ? (k: U) => unknown : never
9+
) extends (k: infer I) => unknown
10+
? I
11+
: never;
12+
13+
interface ClassSpec {
14+
public?: object;
15+
private?: object;
16+
publicExtends?: Record<string, ClassSpec>;
17+
privateExtends?: Record<string, ClassSpec>;
18+
}
19+
20+
type MaybeMergePrivateSuperSpec<T> = T extends Record<string, ClassSpec>
21+
? MergePrivateSuperSpec<T>
22+
: {};
23+
24+
type MaybeMergePrivateSpecs<T extends ClassSpec, U> = U extends ClassSpec
25+
? MergePrivateSpecs<U, T>
26+
: T;
27+
28+
type MergePrivateSpecs<T extends ClassSpec, U extends ClassSpec> = {
29+
public: T["public"] & U["public"];
30+
private: T["private"] & U["private"];
31+
};
32+
33+
type MergePrivateSuperSpec<T extends Record<string, ClassSpec>> =
34+
UnionToIntersection<
35+
{
36+
[P in keyof T]: SimplifyPrivateSpec<T[P]>;
37+
}[keyof T]
38+
>;
39+
40+
export type SimplifyPrivateSpec<T extends ClassSpec> = MaybeMergePrivateSpecs<
41+
MaybeMergePrivateSpecs<T, MaybeMergePrivateSuperSpec<T["publicExtends"]>>,
42+
MaybeMergePrivateSuperSpec<T["privateExtends"]>
43+
>;
44+
45+
// repro from https://github.com/microsoft/TypeScript/issues/43877#issuecomment-866146516
46+
47+
type Converted<T> = {
48+
[P in keyof T]: null extends T[P] ? T[P] : T[P];
49+
};
50+
51+
type DefaultsDeep<T, U extends T> = {
52+
[P in keyof T]-?: U[P] extends T[P]
53+
? null extends U[P]
54+
? Converted<DefaultsDeep<T[P], NonNullable<U[P]>>>
55+
: T[P]
56+
: T[P];
57+
};
58+
59+
interface _Array<T> {
60+
find<S extends T>(predicate: (value: T) => boolean): void;
61+
}
62+
63+
const z: _Array<DefaultsDeep<{}, {}>> = [];
64+
65+
z.find((_) => true);

0 commit comments

Comments
 (0)