I’m trying to define a generic zip function:
type ZippedElement<T extends unknown[][]> = {
[K in keyof T]: T[K] extends (infer V)[] ? V : never;
};
export function zip<T extends unknown[][]>(...args: T) {
const minLength = Math.min(...args.map((arr) => arr.length));
return Array.from({ length: minLength }, (_, i) =>
args.map((arr) => arr[i]),
) as ZippedElement<T>[];
}
It seems to work with dynamic arrays:
const a: number[] = ...;
const b: string[] = ...;
zip(a, b) // ==> [number, string][]
But I want my type checking to also infer tuple when possible, so I want this to work too:
const a: [number, number] = [1, 2];
const b: [string, string] = ["a", "b"];
zip(a, b) // ==> [[number, string], [number, string]]
I created myself an utility for creating a tuple of a particular size:
type StaticArray<L extends number, T, R extends any[] = []> =
R extends { length: L }
? R
: StaticArray<L, T, [...R, T]>;
All that would be missing is a type that takes T extends unknown[][]
and returns a tuple of the minimum size of all tuple if all parameters are tuple, and return an array if there’s one array in the inputs:
type ZippedTupleOrArray<T extends unknown[][]> =
T extends /* magic infer minimum tuple size N */
? StaticArray<ZippedElement<T>, N>
: Array<ZippedElement<T>>;
Is it actually possible to implement? If so, how?