A simple trick to iterate over a tuple in TypeScript without resorting to recursion.
When creating a type derived from a tuple, the obvious method that comes to mind is through recursion i.e. something like this:
/**
* Assuming the data here would be like
* [ ["Name", "Description", "Age"], ... ]
**/
type DeserialisedList<T extends string[][]> = T extends
[infer First extends string[], ...infer Rest extends string[][]]
? [DeserialisedRecord<First>, ...DeserialisedList<Rest>]
: [];
type DeserialisedRecord<T extends string[]> = T extends
[infer Name, infer Description, infer Age]
? { name: Name; description: Description; age: StringToNumber<Age> }
: never;
This approach works fine for a record with a fewer entries. It can, however, become a problem as the size of the data increases.
TypeScript imposes recursion limits to prevent excessive compile-time computations, as deeply nested types or infinite recursion can significantly impact performance and lead to compiler crashes. These limits ensure that type-checking remains efficient and manageable.
To work around this we can use mapped types.
Mapped types let you create an object with keys that are part of a union. The indices of a list correspond to the keys of an Array object. So we use that,
type FormatNames<T extends readonly [string, string, string][]> = {
[key in keyof T]: DeserialisedRecord<T[key]>;
};
This approach works with a huge amount of data too, since there is no recursion at all.
The output of both the approaches looks identical for a lesser amount of data. This is what I used for my submission to Advent of TypeScript Day 12!