UPDATE for TypeScript 4.5:
With the introduction of recursive conditional types and tail recursion elimination, defining a type like Flatten<T>
to flatten arbitrary arrays becomes more straightforward.
type Flatten<T extends readonly any[], A extends readonly any[] = []> =
T extends [infer F, ...infer R] ?
Flatten<R, F extends readonly any[] ? [...A, ...F] : [...A, F]> :
A
type InputTuple = [A, B, [C, D], [A, B, D], [A, B, C, D, B], A];
type FlattenedTuple = Flatten<InputTuple>;
// Output: [A, B, C, D, A, B, D, A, B, C, D, B, A]
You can even achieve deep flattening by adding another layer of recursion as demonstrated below:
type FlattenDeep<T extends readonly any[], A extends readonly any[] = []> =
T extends [infer F, ...infer R] ?
FlattenDeep<R, F extends readonly any[] ? [...A, ...FlattenDeep<F>] : [...A, F]> :
A
type InputDeepTuple = [A, B, [C, D], [A, B, D], [A, B, [[C], D], [B]], A];
type FlattenedDeepTuple = FlattenDeep<InputTuple>;
// Output: [A, B, C, D, A, B, D, A, B, C, D, B, A]
To test or play around with this code snippet, feel free to click on this interactive Playground link.
Answer for TypeScript 4.0:
In TypeScript 4.0, variadic tuple types are introduced which allow for simple concatenation of fixed tuples. Here's a basic implementation of Flatten<T>
:
type ConcatX<T extends readonly (readonly any[])[]> = [
...T[0], ...T[1], ...T[2], ...T[3], ...T[4],
...T[5], ...T[6], ...T[7], ...T[8], ...T[9],
...T[10], ...T[11], ...T[12], ...T[13], ...T[14],
...T[15], ...T[16], ...T[17], ...T[18], ...T[19]
];
type Flatten<T extends readonly any[]> =
ConcatX<[...{ [K in keyof T]: T[K] extends any[] ? T[K] : [T[K]] }, ...[][]]>
type InputTuple = [A, B, [C, D], [A, B, D], [A, B, C, D, B], A];
type FlattenedTuple = Flatten<InputTuple>;
// Output: [A, B, C, D, A, B, D, A, B, C, D, B, A]
You can experiment with this code here.
Pre-TypeScript 4.0 Update:
Working with complex types like nested arrays in TypeScript poses challenges due to limitations in the type system. While there are clever workarounds involving recursive conditional types, it's important to note that these approaches may not be future-proof and could impact compiler performance significantly. Officially, TypeScript does not support certain operations on tuples, such as recursive flattening.
The community, however, continues to explore solutions, with libraries like ts-toolbelt
offering advanced tuple manipulation features. Proceed with caution when implementing non-standard tuples in your projects.