When we talk about "zip," it usually refers to a convolution, which involves converting ordered pairs (or triplets, etc.) of arrays into an array of ordered pairs (or triplets, etc.). For examples, you can check out Python's zip()
or Haskell's zip
.
If we want to zip tuple types in TypeScript without considering cases where the tuples have different lengths, here is one way to do it:
type ZipTuple<T extends readonly any[], U extends readonly any[]> = {
[K in keyof T]: [T[K], K extends keyof U ? U[K] : never]
}
This uses the mapped tuple/array feature introduced in TS3.1.
The result is as follows:
type Keys = ['name', 'age', 'height']
type Values = [string, number, number]
type KVTuple = ZipTuple<Keys, Values>;
// type KVTuple = [["name", string], ["age", number], ["height", number]]
With this information, we can define KeyValTuplesToObject<K, V>
, which takes a tuple K
of keys and a tuple V
of values of the same length to produce an object type where each key corresponds to the 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
This first uses ZipTuple
to convert the keys and values tuples into key-value pairs, then creates a mapped type that extracts the corresponding value for each key from these tuples.
In TS4.1, there is an update for KeyValTuplesToObject
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
as before, we get:
type KVObject = KeyValTuplesToObject<Keys, Values>
/* type KVObject = {
name: string;
age: number;
height: number;
} */
Seems like everything is working well. Hopefully, this explanation was helpful!
Link to code