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>>