Typescript: Can I define an n-length tuple type?
Update:
With Recursive conditional types (added in TypeScript 4.1.0) it is possible to:
type Tuple<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
type Tuple9<T> = Tuple<T, 9>;
type Board9x9<P> = Tuple9<Tuple9<P>>;
Playground
Original answer:
Typescript 3 introduces rest elements in tuple types
The last element of a tuple type can be a rest element of the form ...X, where X is an array type
To restrict the length of a tuple we can use intersection with { length: N }
type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };
type Tuple9<T> = Tuple<T, 9>;
type Board9x9<P> = Tuple9<Tuple9<P>>;
This works when variable of Tuple
type is being initialized:
const t: Tuple<number, 1> = [1, 1] // error: 'length' incompatible.
A caveat here, typescript won't warn you if you'll try to access non element at index out of tuple range:
declare const customTuple: Tuple<number, 1>;
customTuple[10] // no error here unfortunately
declare const builtinTuple: [number];
builtinTuple[10] // error: has no element at index '10'
There's a suggestion to add a generic way to specify length of a tuple type.
One quick simplification would be to create a Tuple9
type, that can be used to create the first level as well as the second level of the matrix:
type Tuple9<T> = [T, T, T, T, T, T, T, T, T]
type Board9x9<P> = Tuple9<Tuple9<P>>