Normally the term "zip" refers to a convolution, where you turn an ordered pair (or triplet, etc) of arrays into an array of ordered pairs (or triplets, etc). See Python's zip()
, Haskell's zip
for examples.
One way to zip tuple types in TypeScript, neglecting the edge cases where the tuples are of differing lengths, is as follows:
type ZipTuple<T extends readonly any[], U extends readonly any[]> = {
[K in keyof T]: [T[K], K extends keyof U ? U[K] : never]
}
We're just using the mapped tuple/array feature added in TS3.1.
That produces the following:
type Keys = ['name', 'age', 'height']
type Values = [string, number, number]
type KVTuple = ZipTuple<Keys, Values>;
// type KVTuple = [["name", string], ["age", number], ["height", number]]
Armed with that, we can define KeyValTuplesToObject<K, V>
which takes a tuple K
of keys and a same-length tuple V
of values and produce the object type where each key maps to the corresponding value:
type KeyValTuplesToObject<K extends readonly PropertyKey[], V extends readonly any[]> =
ZipTuple<K, V>[number] extends infer Z ?
[Z] extends [[any, any]] ? { [P in Z[0]]: Extract<Z, [P, any]>[1] } : never : never
That first uses ZipTuple
to convert the keys and value tuples to a tuple of key-value pairs, indexes into it with [number]
to get the key-value tuples as a union, and then makes a mapped type that iterates over all the keys in these tuples and extracts the value from the corresponding element.
UPDATE for TS4.1; the above KeyValTuplesToObject
can be simiplified using key remapping in mapped types:
type KeyValTuplesToObject<K extends readonly PropertyKey[], V extends readonly any[]> =
{ [T in ZipTuple<K, V>[number]as T[0]]: T[1] };
Using the same Keys
and Values
from before, this is the outcome:
type KVObject = KeyValTuplesToObject<Keys, Values>
/* type KVObject = {
name: string;
age: number;
height: number;
} */
Looks good to me. Hope that helps; good luck!
Link to code