Description
Search Terms
tuple, type, length
Suggestion
I'd like to see a way to specify the length of a tuple or array type when declaring it. For short tuples, it may be viable to write them out by hand like [number, number]
, but whenever the length is longer (say 10+), it becomes a chore.
Using the following approach to define a fixed-length tuple
// @ts-ignore interface can only extend interface or class
interface FixedLengthArray<T extends any[], L extends number> extends T {
length: L;
}
has a few drawbacks:
1.: we cannot extend T because its not an interface or class.
2.: when ignoring that error, tuple literals are not inferred as tuples but as arrays when assigning them:
type Foo = FixedLengthArray<number[], 5>;
const foo1: Foo = [1, 2, 3, 4, 5]; // error: length is not compatible, number not assignable to 5
const foo2: Foo = [1, 2, 3, 4, 5] as [1, 2, 3, 4, 5]; // works, but defeats the purpose of that fixed-length
On the other hand, when using manually-written tuples, this works:
type Bar = [number, number, number, number, number];
const bar1: Bar = [1, 2, 3, 4, 5]; // no error
Use Cases
- Declaring fixed-length tuples or arrays with a large number of items
- Creating a Range union (e.g.
0 | 1 | 2 | 3 | 4
from the keys of such a type) without having to resort to recursive types (currently broken, see TSServer hangs when using recursive types on tuples and pressing "," #26155)
Examples
I'll leave the syntax up for discussion, and provide the length in the square brackets for now:
type T1 = number[3]; // equals [number, number, number]
type K1 = keyof T1; // 0 | 1 | 2
type T2 = number[100]; // equals [number, number, ..., number] (100 items total)
type K2 = keyof T2; // 0 | 1 | ... | 99
type T3 = any[0]; // equals [ ], type annotation is somewhat obsolete here
type K3 = keyof T3; // never
The basic rules for tuple assignability should apply, as if the types were written out by hand.
Related:
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript / JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. new expression-level syntax)