Handle heterogeneous arrays in flat and flatMap #24579
Description
The typings for both flat and flatMap work ok for homogeneous arrays but do not handle tuple types well. Consider the current typings (with rename):
declare let arr: [[number, boolean], string];
let x0 = arr.flatten(0); // (string | [ number, boolean ])[]
let x1 = arr.flatten(1); // error
let x2 = arr.flatten(2); // errorUsing conditional types and infer we can start to see a solution like:
type Flatten0<T> = T extends Array<infer U> ? Array<U> : never;
type Flatten1<T> = T extends Array<infer U>
? U extends Array<any> ? Flatten0<U> : never
: never;
type Flatten2<T> = T extends Array<infer U>
? U extends Array<any> ? Flatten1<U> : never
: never;
interface Array<T> {
flat<T>(this: T, depth: 2): Flatten2<T>;
flat<T>(this: T, depth: 1): Flatten1<T>;
flat<T>(this: T, depth: 0): Flatten0<T>;
flat<T>(this: T, depth: number): Array<T>
}Which works great for array types and handles some tuple types better, but sacrifices a type error on the depth parameter when the array isn't nested that much, and more importantly, doesn't handle heterogeneous tuple cases, e.g. [ [string, number], boolean] should flatten to [string, number, boolean]. As far as I can tell, this is not possible without variadic kinds. Additionally, this implementation would benefit hugely from a way to reference a type recursively, e.g. https://github.com/Microsoft/TypeScript/issues/6230 (I'm not the only one to notice this issue trying to type this API).
Activity
HerringtonDarkholme commentedon Jun 28, 2018
Would #24897 solve this? Currently it seems very hard to recurse on tuple types though...
mhegazy commentedon Jun 28, 2018
Herrington Darkholme (@HerringtonDarkholme) not sure how that would be used.. do you have a proposal in mind?
HerringtonDarkholme commentedon Jun 30, 2018
The basic idea is to abuse tuple type to perform type level programming. But I'm quite sure it isn't desirable solution, indeed.
First we can transform number literal type to tuple type, which can be used to model the
depthparameter. Thelengthproperty in tuple is the key of transformation.Then we can use a tuple to indicate flat depth.
We also need make a type to concatenate two tuple types, crafted here. #24897 (comment)
And finally we can model flat tuple type:
I didn't managed to pass generic instantiation check, expectedly.
(But I just can't help my self from doing this...
RyanCavanaugh commentedon Jan 31, 2020
Rolling into #36554