forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspreadTupleUnionDistribution.types
More file actions
151 lines (126 loc) · 5.18 KB
/
spreadTupleUnionDistribution.types
File metadata and controls
151 lines (126 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//// [tests/cases/conformance/types/spread/spreadTupleUnionDistribution.ts] ////
=== spreadTupleUnionDistribution.ts ===
// Repro from #62812
// Spread operator fails to distribute over union when recursive type call is inlined instead of aliased
type CrossProduct<Union, Counter extends unknown[]> =
>CrossProduct : CrossProduct<Union, Counter>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Counter extends [infer Zero, ...infer Rest]
? (Union extends infer Member
? [Member, ...CrossProduct<Union, Rest>]
: never)
: [];
// Basic test - this works
let test1: CrossProduct<number | string, [undefined]>; // [string] | [number]
>test1 : [string] | [number]
> : ^^^^^^^^^^^^^^^^^^^
type Depth1 = CrossProduct<number | string, [undefined]> // [string] | [number]
>Depth1 : [string] | [number]
> : ^^^^^^^^^^^^^^^^^^^
// With alias - this should work and give full cross product
let test2: (number | string extends infer Union ? (Union extends unknown ? [Union, ...Depth1]: never) : never);
>test2 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Expected: [string, string] | [number, number] | [string, number] | [number, string]
// With inlined type - this should also work but currently doesn't distribute properly
let test3: (number | string extends infer Union ? (Union extends unknown ? [Union, ...CrossProduct<number | string, [undefined]>]: never) : never);
>test3 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Expected: [string, string] | [number, number] | [string, number] | [number, string]
// Actual (bug): [string, string] | [number, number]
// With literal union - this works
let test4: (number | string extends infer Union ? (Union extends unknown ? [Union, ...([string] | [number])]: never) : never);
>test4 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Expected: [string, string] | [number, number] | [string, number] | [number, string]
// Test that the types are actually correct by checking assignability
type Expected = [string, string] | [number, number] | [string, number] | [number, string];
>Expected : Expected
> : ^^^^^^^^
// These should all be true (no error)
type Test1Check = Expected extends typeof test2 ? true : false;
>Test1Check : true
> : ^^^^
>test2 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
type Test2Check = typeof test2 extends Expected ? true : false;
>Test2Check : true
> : ^^^^
>test2 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
// If the bug is fixed, these will also be true (no error)
type Test3Check = Expected extends typeof test3 ? true : false;
>Test3Check : true
> : ^^^^
>test3 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
type Test4Check = typeof test3 extends Expected ? true : false;
>Test4Check : true
> : ^^^^
>test3 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
type Test5Check = Expected extends typeof test4 ? true : false;
>Test5Check : true
> : ^^^^
>test4 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
type Test6Check = typeof test4 extends Expected ? true : false;
>Test6Check : true
> : ^^^^
>test4 : [string, string] | [string, number] | [number, string] | [number, number]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>true : true
> : ^^^^
>false : false
> : ^^^^^
// Force an error if checks fail
const _check1: Test1Check = true;
>_check1 : true
> : ^^^^
>true : true
> : ^^^^
const _check2: Test2Check = true;
>_check2 : true
> : ^^^^
>true : true
> : ^^^^
const _check3: Test3Check = true; // This will error if bug exists
>_check3 : true
> : ^^^^
>true : true
> : ^^^^
const _check4: Test4Check = true; // This will error if bug exists
>_check4 : true
> : ^^^^
>true : true
> : ^^^^
const _check5: Test5Check = true;
>_check5 : true
> : ^^^^
>true : true
> : ^^^^
const _check6: Test6Check = true;
>_check6 : true
> : ^^^^
>true : true
> : ^^^^