Skip to content

Commit 30b46c8

Browse files
committed
Better typings for Array.concat(), etc.
1 parent 20e2be1 commit 30b46c8

37 files changed

+146
-200
lines changed

src/harness/fourslash.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4685,6 +4685,7 @@ namespace FourSlashInterface {
46854685
varEntry("JSON"),
46864686
interfaceEntry("ReadonlyArray"),
46874687
interfaceEntry("ConcatArray"),
4688+
typeEntry("ConcatFlatten"),
46884689
varEntry("Array"),
46894690
interfaceEntry("ArrayConstructor"),
46904691
interfaceEntry("TypedPropertyDescriptor"),

src/lib/es2019.array.d.ts

Lines changed: 42 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
type Flatten<T> = T extends readonly (infer U)[] ? U : T;
2+
13
interface ReadonlyArray<T> {
24

35
/**
@@ -11,105 +13,81 @@ interface ReadonlyArray<T> {
1113
* thisArg is omitted, undefined is used as the this value.
1214
*/
1315
flatMap<U, This = undefined> (
14-
callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray<U>,
16+
callback: (this: This, value: T, index: number, array: T[]) => U,
1517
thisArg?: This
16-
): U[]
17-
18+
): Flatten<U>[]
1819

1920
/**
2021
* Returns a new array with all sub-array elements concatenated into it recursively up to the
2122
* specified depth.
2223
*
2324
* @param depth The maximum recursion depth
2425
*/
25-
flat<U>(this:
26-
ReadonlyArray<U[][][][]> |
27-
28-
ReadonlyArray<ReadonlyArray<U[][][]>> |
29-
ReadonlyArray<ReadonlyArray<U[][]>[]> |
30-
ReadonlyArray<ReadonlyArray<U[]>[][]> |
31-
ReadonlyArray<ReadonlyArray<U>[][][]> |
32-
33-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U[][]>>> |
34-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>[][]>> |
35-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>[][]> |
36-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>[]>[]> |
37-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U[]>>[]> |
38-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U[]>[]>> |
39-
40-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U[]>>>> |
41-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U>[]>>> |
42-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>[]>> |
43-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>>[]> |
44-
45-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>>>>,
46-
depth: 4): U[];
26+
flat<U extends readonly any[]>(this: U, depth: 7): Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>>>[];
4727

4828
/**
4929
* Returns a new array with all sub-array elements concatenated into it recursively up to the
5030
* specified depth.
5131
*
5232
* @param depth The maximum recursion depth
5333
*/
54-
flat<U>(this:
55-
ReadonlyArray<U[][][]> |
56-
57-
ReadonlyArray<ReadonlyArray<U>[][]> |
58-
ReadonlyArray<ReadonlyArray<U[]>[]> |
59-
ReadonlyArray<ReadonlyArray<U[][]>> |
34+
flat<U extends readonly any[]>(this: U, depth: 6): Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>>[];
6035

61-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U[]>>> |
62-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>[]>> |
63-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>[]> |
64-
65-
ReadonlyArray<ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>>>,
66-
depth: 3): U[];
36+
/**
37+
* Returns a new array with all sub-array elements concatenated into it recursively up to the
38+
* specified depth.
39+
*
40+
* @param depth The maximum recursion depth
41+
*/
42+
flat<U extends readonly any[]>(this: U, depth: 5): Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>[];
6743

6844
/**
6945
* Returns a new array with all sub-array elements concatenated into it recursively up to the
7046
* specified depth.
7147
*
7248
* @param depth The maximum recursion depth
7349
*/
74-
flat<U>(this:
75-
ReadonlyArray<U[][]> |
50+
flat<U extends readonly any[]>(this: U, depth: 4): Flatten<Flatten<Flatten<Flatten<U[number]>>>>[];
7651

77-
ReadonlyArray<ReadonlyArray<U[]>> |
78-
ReadonlyArray<ReadonlyArray<U>[]> |
52+
/**
53+
* Returns a new array with all sub-array elements concatenated into it recursively up to the
54+
* specified depth.
55+
*
56+
* @param depth The maximum recursion depth
57+
*/
58+
flat<U extends readonly any[]>(this: U, depth: 3): Flatten<Flatten<Flatten<U[number]>>>[];
7959

80-
ReadonlyArray<ReadonlyArray<ReadonlyArray<U>>>,
81-
depth: 2): U[];
60+
/**
61+
* Returns a new array with all sub-array elements concatenated into it recursively up to the
62+
* specified depth.
63+
*
64+
* @param depth The maximum recursion depth
65+
*/
66+
flat<U extends readonly any[]>(this: U, depth: 2): Flatten<Flatten<U[number]>>[];
8267

8368
/**
8469
* Returns a new array with all sub-array elements concatenated into it recursively up to the
8570
* specified depth.
8671
*
8772
* @param depth The maximum recursion depth
8873
*/
89-
flat<U>(this:
90-
ReadonlyArray<U[]> |
91-
ReadonlyArray<ReadonlyArray<U>>,
92-
depth?: 1
93-
): U[];
74+
flat<U extends readonly any[]>(this: U, depth?: 1): Flatten<U[number]>[];
9475

9576
/**
9677
* Returns a new array with all sub-array elements concatenated into it recursively up to the
9778
* specified depth.
9879
*
9980
* @param depth The maximum recursion depth
10081
*/
101-
flat<U>(this:
102-
ReadonlyArray<U>,
103-
depth: 0
104-
): U[];
82+
flat<U extends readonly any[]>(this: U, depth: 0): U[number][];
10583

10684
/**
10785
* Returns a new array with all sub-array elements concatenated into it recursively up to the
10886
* specified depth. If no depth is provided, flat method defaults to the depth of 1.
10987
*
11088
* @param depth The maximum recursion depth
11189
*/
112-
flat<U>(depth?: number): any[];
90+
flat(this: readonly any[], depth: number): any[];
11391
}
11492

11593
interface Array<T> {
@@ -125,79 +103,79 @@ interface Array<T> {
125103
* thisArg is omitted, undefined is used as the this value.
126104
*/
127105
flatMap<U, This = undefined> (
128-
callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray<U>,
106+
callback: (this: This, value: T, index: number, array: T[]) => U,
129107
thisArg?: This
130-
): U[]
108+
): Flatten<U>[]
131109

132110
/**
133111
* Returns a new array with all sub-array elements concatenated into it recursively up to the
134112
* specified depth.
135113
*
136114
* @param depth The maximum recursion depth
137115
*/
138-
flat<U>(this: U[][][][][][][][], depth: 7): U[];
116+
flat<U extends readonly any[]>(this: U, depth: 7): Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>>>[];
139117

140118
/**
141119
* Returns a new array with all sub-array elements concatenated into it recursively up to the
142120
* specified depth.
143121
*
144122
* @param depth The maximum recursion depth
145123
*/
146-
flat<U>(this: U[][][][][][][], depth: 6): U[];
124+
flat<U extends readonly any[]>(this: U, depth: 6): Flatten<Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>>[];
147125

148126
/**
149127
* Returns a new array with all sub-array elements concatenated into it recursively up to the
150128
* specified depth.
151129
*
152130
* @param depth The maximum recursion depth
153131
*/
154-
flat<U>(this: U[][][][][][], depth: 5): U[];
132+
flat<U extends readonly any[]>(this: U, depth: 5): Flatten<Flatten<Flatten<Flatten<Flatten<U[number]>>>>>[];
155133

156134
/**
157135
* Returns a new array with all sub-array elements concatenated into it recursively up to the
158136
* specified depth.
159137
*
160138
* @param depth The maximum recursion depth
161139
*/
162-
flat<U>(this: U[][][][][], depth: 4): U[];
140+
flat<U extends readonly any[]>(this: U, depth: 4): Flatten<Flatten<Flatten<Flatten<U[number]>>>>[];
163141

164142
/**
165143
* Returns a new array with all sub-array elements concatenated into it recursively up to the
166144
* specified depth.
167145
*
168146
* @param depth The maximum recursion depth
169147
*/
170-
flat<U>(this: U[][][][], depth: 3): U[];
148+
flat<U extends readonly any[]>(this: U, depth: 3): Flatten<Flatten<Flatten<U[number]>>>[];
171149

172150
/**
173151
* Returns a new array with all sub-array elements concatenated into it recursively up to the
174152
* specified depth.
175153
*
176154
* @param depth The maximum recursion depth
177155
*/
178-
flat<U>(this: U[][][], depth: 2): U[];
156+
flat<U extends readonly any[]>(this: U, depth: 2): Flatten<Flatten<U[number]>>[];
179157

180158
/**
181159
* Returns a new array with all sub-array elements concatenated into it recursively up to the
182160
* specified depth.
183161
*
184162
* @param depth The maximum recursion depth
185163
*/
186-
flat<U>(this: U[][], depth?: 1): U[];
164+
flat<U extends readonly any[]>(this: U, depth?: 1): Flatten<U[number]>[];
187165

188166
/**
189167
* Returns a new array with all sub-array elements concatenated into it recursively up to the
190168
* specified depth.
191169
*
192170
* @param depth The maximum recursion depth
193171
*/
194-
flat<U>(this: U[], depth: 0): U[];
172+
flat<U extends readonly any[]>(this: U, depth: 0): U[number][];
195173

196174
/**
197175
* Returns a new array with all sub-array elements concatenated into it recursively up to the
198176
* specified depth. If no depth is provided, flat method defaults to the depth of 1.
199177
*
200178
* @param depth The maximum recursion depth
201179
*/
202-
flat<U>(depth?: number): any[];
180+
flat(this: readonly any[], depth: number): any[];
203181
}

src/lib/es5.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ interface ReadonlyArray<T> {
10851085
* Combines two or more arrays.
10861086
* @param items Additional items to add to the end of array1.
10871087
*/
1088-
concat(...items: (T | ConcatArray<T>)[]): T[];
1088+
concat<U extends any[]>(...items: U): (T | ConcatFlatten<U[number]>)[];
10891089
/**
10901090
* Adds all the elements of an array separated by the specified separator string.
10911091
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
@@ -1181,6 +1181,7 @@ interface ConcatArray<T> {
11811181
join(separator?: string): string;
11821182
slice(start?: number, end?: number): T[];
11831183
}
1184+
type ConcatFlatten<T> = T extends ConcatArray<infer U> ? U : T;
11841185

11851186
interface Array<T> {
11861187
/**
@@ -1213,7 +1214,7 @@ interface Array<T> {
12131214
* Combines two or more arrays.
12141215
* @param items Additional items to add to the end of array1.
12151216
*/
1216-
concat(...items: (T | ConcatArray<T>)[]): T[];
1217+
concat<U extends any[]>(...items: U): (T | ConcatFlatten<U[number]>)[];
12171218
/**
12181219
* Adds all the elements of an array separated by the specified separator string.
12191220
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.

tests/baselines/reference/arrayConcat2.types

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ var a: string[] = [];
55

66
a.concat("hello", 'world');
77
>a.concat("hello", 'world') : string[]
8-
>a.concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
8+
>a.concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
99
>a : string[]
10-
>concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
10+
>concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
1111
>"hello" : "hello"
1212
>'world' : "world"
1313

1414
a.concat('Hello');
1515
>a.concat('Hello') : string[]
16-
>a.concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
16+
>a.concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
1717
>a : string[]
18-
>concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
18+
>concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
1919
>'Hello' : "Hello"
2020

2121
var b = new Array<string>();
@@ -25,8 +25,8 @@ var b = new Array<string>();
2525

2626
b.concat('hello');
2727
>b.concat('hello') : string[]
28-
>b.concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
28+
>b.concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
2929
>b : string[]
30-
>concat : { (...items: ConcatArray<string>[]): string[]; (...items: (string | ConcatArray<string>)[]): string[]; }
30+
>concat : { (...items: ConcatArray<string>[]): string[]; <U extends any[]>(...items: U): (string | ConcatFlatten<U[number]>)[]; }
3131
>'hello' : "hello"
3232

tests/baselines/reference/arrayConcat3.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ function doStuff<T extends object, T1 extends T>(a: Array<Fn<T>>, b: Array<Fn<T1
1111

1212
b.concat(a);
1313
>b.concat(a) : Fn<T1>[]
14-
>b.concat : { (...items: ConcatArray<Fn<T1>>[]): Fn<T1>[]; (...items: (Fn<T1> | ConcatArray<Fn<T1>>)[]): Fn<T1>[]; }
14+
>b.concat : { (...items: ConcatArray<Fn<T1>>[]): Fn<T1>[]; <U extends any[]>(...items: U): (Fn<T1> | ConcatFlatten<U[number]>)[]; }
1515
>b : Fn<T1>[]
16-
>concat : { (...items: ConcatArray<Fn<T1>>[]): Fn<T1>[]; (...items: (Fn<T1> | ConcatArray<Fn<T1>>)[]): Fn<T1>[]; }
16+
>concat : { (...items: ConcatArray<Fn<T1>>[]): Fn<T1>[]; <U extends any[]>(...items: U): (Fn<T1> | ConcatFlatten<U[number]>)[]; }
1717
>a : Fn<T>[]
1818
}
1919

tests/baselines/reference/arrayConcatMap.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ var x = [].concat([{ a: 1 }], [{ a: 2 }])
44
>[].concat([{ a: 1 }], [{ a: 2 }]) .map(b => b.a) : any[]
55
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
66
>[].concat([{ a: 1 }], [{ a: 2 }]) : any[]
7-
>[].concat : { (...items: ConcatArray<any>[]): any[]; (...items: any[]): any[]; }
7+
>[].concat : { (...items: ConcatArray<any>[]): any[]; <U extends any[]>(...items: U): any[]; }
88
>[] : undefined[]
9-
>concat : { (...items: ConcatArray<any>[]): any[]; (...items: any[]): any[]; }
9+
>concat : { (...items: ConcatArray<any>[]): any[]; <U extends any[]>(...items: U): any[]; }
1010
>[{ a: 1 }] : { a: number; }[]
1111
>{ a: 1 } : { a: number; }
1212
>a : number

tests/baselines/reference/arrayFlatMap.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ const readonlyArray: ReadonlyArray<number> = [];
99

1010
array.flatMap((): ReadonlyArray<number> => []); // ok
1111
>array.flatMap((): ReadonlyArray<number> => []) : number[]
12-
>array.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
12+
>array.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => Flatten<U>[]
1313
>array : number[]
14-
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
14+
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => Flatten<U>[]
1515
>(): ReadonlyArray<number> => [] : () => readonly number[]
1616
>[] : undefined[]
1717

1818
readonlyArray.flatMap((): ReadonlyArray<number> => []); // ok
1919
>readonlyArray.flatMap((): ReadonlyArray<number> => []) : number[]
20-
>readonlyArray.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
20+
>readonlyArray.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => Flatten<U>[]
2121
>readonlyArray : readonly number[]
22-
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
22+
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => Flatten<U>[]
2323
>(): ReadonlyArray<number> => [] : () => readonly number[]
2424
>[] : undefined[]
2525

tests/baselines/reference/arrayOfSubtypeIsAssignableToReadonlyArray.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(13,1): error TS2322: Type 'A[]' is not assignable to type 'readonly B[]'.
22
Property 'b' is missing in type 'A' but required in type 'B'.
33
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
4-
The types returned by 'concat(...)' are incompatible between these types.
4+
The types returned by 'slice(...)' are incompatible between these types.
55
Type 'A[]' is not assignable to type 'B[]'.
66
Type 'A' is not assignable to type 'B'.
77

@@ -31,7 +31,7 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
3131
rrb = cra; // error: 'A' is not assignable to 'B'
3232
~~~
3333
!!! error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
34-
!!! error TS2322: The types returned by 'concat(...)' are incompatible between these types.
34+
!!! error TS2322: The types returned by 'slice(...)' are incompatible between these types.
3535
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
3636
!!! error TS2322: Type 'A' is not assignable to type 'B'.
3737

tests/baselines/reference/concatError.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ fa = fa.concat([0]);
1515
>fa = fa.concat([0]) : number[]
1616
>fa : number[]
1717
>fa.concat([0]) : number[]
18-
>fa.concat : { (...items: ConcatArray<number>[]): number[]; (...items: (number | ConcatArray<number>)[]): number[]; }
18+
>fa.concat : { (...items: ConcatArray<number>[]): number[]; <U extends any[]>(...items: U): (number | ConcatFlatten<U[number]>)[]; }
1919
>fa : number[]
20-
>concat : { (...items: ConcatArray<number>[]): number[]; (...items: (number | ConcatArray<number>)[]): number[]; }
20+
>concat : { (...items: ConcatArray<number>[]): number[]; <U extends any[]>(...items: U): (number | ConcatFlatten<U[number]>)[]; }
2121
>[0] : number[]
2222
>0 : 0
2323

2424
fa = fa.concat(0);
2525
>fa = fa.concat(0) : number[]
2626
>fa : number[]
2727
>fa.concat(0) : number[]
28-
>fa.concat : { (...items: ConcatArray<number>[]): number[]; (...items: (number | ConcatArray<number>)[]): number[]; }
28+
>fa.concat : { (...items: ConcatArray<number>[]): number[]; <U extends any[]>(...items: U): (number | ConcatFlatten<U[number]>)[]; }
2929
>fa : number[]
30-
>concat : { (...items: ConcatArray<number>[]): number[]; (...items: (number | ConcatArray<number>)[]): number[]; }
30+
>concat : { (...items: ConcatArray<number>[]): number[]; <U extends any[]>(...items: U): (number | ConcatFlatten<U[number]>)[]; }
3131
>0 : 0
3232

3333

tests/baselines/reference/concatTuples.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ ijs = ijs.concat([[3, 4], [5, 6]]);
1010
>ijs = ijs.concat([[3, 4], [5, 6]]) : [number, number][]
1111
>ijs : [number, number][]
1212
>ijs.concat([[3, 4], [5, 6]]) : [number, number][]
13-
>ijs.concat : { (...items: ConcatArray<[number, number]>[]): [number, number][]; (...items: ([number, number] | ConcatArray<[number, number]>)[]): [number, number][]; }
13+
>ijs.concat : { (...items: ConcatArray<[number, number]>[]): [number, number][]; <U extends any[]>(...items: U): ([number, number] | ConcatFlatten<U[number]>)[]; }
1414
>ijs : [number, number][]
15-
>concat : { (...items: ConcatArray<[number, number]>[]): [number, number][]; (...items: ([number, number] | ConcatArray<[number, number]>)[]): [number, number][]; }
15+
>concat : { (...items: ConcatArray<[number, number]>[]): [number, number][]; <U extends any[]>(...items: U): ([number, number] | ConcatFlatten<U[number]>)[]; }
1616
>[[3, 4], [5, 6]] : [number, number][]
1717
>[3, 4] : [number, number]
1818
>3 : 3

0 commit comments

Comments
 (0)