## Search Terms generic mapped tuple types overrides ## Suggestion The syntax here is up for debate, but the basic idea is to be able to apply the idea behind mapped object types to tuples. I would suggest the following: ```ts type MappedTuple<T extends any[]> = [F<E> for E in T]; ``` This would apply a type mapping to each of the element types of the tuple. For example: ```ts type PromiseTuple<T extends any[]> = [Promise<E> for E in T]; type T1 = Promise<[number, string, boolean]>; // [Promise<number>, Promise<string>, Promise<boolean>] ``` ## Use Cases This would make it much easier to write functions that take a variable number of arguments that all have to conform to some form and be able to reference the underlying type. This eliminates the need to write a ton of overrides: ```ts all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>; all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>; all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>; all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>; ... all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; ``` ## Examples The basic usage of this would be as follows: ```ts type TypeMap<T> = { wrap: T }; type MapTuple<T extends any[]> = [TypeMap<E> for E in T]; type T2 = MapTuple<[number, string, ...boolean[]]> // [{ wrap: number }, { wrap: string }, ...{ wrap: boolean }[]]; ``` There are many compelling examples of how this would simplify library code. For example, above, instead of having 10 overrides for `Promise.all`, we could define it simply as: ```ts type PromiseLikeTuple<T extends any[]> = [E | PromiseLike<E> for E in T]; all<T extends any[]>(...values: PromiseLikeTuple<T>): Promise<T>; ``` Similarly RxJS' `combineLatest` would similarly benefit (Note: I've moved the `project` argument to the head of the list because rest arguments must appear last, this differs from the current definition of `combineLatest`) ```ts type ObservableTuple<T extends any> = [ObservableInput<E> for E in T]; combineLatest<T extends any[], R>(project: (...values: T) => R, ...observables: ObservableTuple<T>): Observable<R>; ``` This is especially useful because there are only 6(?) overrides for `combineLatest` meaning that providing 7 or more observable inputs would mean that your types would no longer be strict. ## Currently I don't believe that it is possible to construct a mapped tuple type currently. This would be made possible with the addition of recursive generic types and made easy to use with the addition of generic generic type arguments: ```ts // Currently possible type Head<T extends any[]> = T extends [infer U, ...any[]] ? U : never; type Tail<T extends any[]> = ((...args: T) => void) extends (head: any, ...tail: infer U) => any ? U : never; // Currently errors type SpecificMapTuple<T extends any[]> = [F<Head<T>>, ...SpecificMapTuple<Tail<T>>]; type GenericMapTuple<F<~>, T extends any[]> =[F<Head<T>>, ...GenericMapTuple<F, Tail<T>>]; function all<T extends any[]>(...values: GenericMapTuple<PromiseLike, T>): Promise<T>; ``` Note: I think adding this functionality via recursive generic types and high order generic type arguments is probably a more flexible and elegant solution that will enable even more interesting typings but it would be nice to have both of those and the mapped tuple types above. ## Checklist My suggestion meets these guidelines: * [x] This wouldn't be a breaking change in existing TypeScript / JavaScript code * [x] This wouldn't change the runtime behavior of existing JavaScript code * [x] This could be implemented without emitting different JS based on the types of the expressions * [x] This isn't a runtime feature (e.g. new expression-level syntax)