9

Typescript in tuple allows to add extra elements with any of types used before, but I would like to limit the length. I've tried with & { length: 2 }, but it didn't helped:

declare var a: [string, number] & { length: 2 };

a[0] = "1"
a[1] = 2;
a[2] = "3";
a[3] = 4;

Assignments for [2] and [3] don't produce error. How can I specify corresponding type?

Qwertiy
  • 19,681
  • 15
  • 61
  • 128
  • Some solutions here : https://stackoverflow.com/questions/41139763/typescript-fixed-length-arraylength-type/59906630#59906630 – colxi Feb 21 '20 at 15:17
  • @colxi, actually there is no such problem starting from version 3.1. – Qwertiy Feb 21 '20 at 15:29
  • Tuples do not prevent you from adding/deleting keys after Array initialization, but there are solutions to implement a safe FixedLengthArray type signatures – colxi Feb 21 '20 at 15:47
  • @colxi, yep, I've understood your answer to that question. – Qwertiy Feb 21 '20 at 16:13

3 Answers3

7

Use type never for array tail:

declare var a: [string, number, ...never[]];

and you'll get

Type '"3"' is not assignable to type 'never'.

Type '4' is not assignable to type 'never'.

Qwertiy
  • 19,681
  • 15
  • 61
  • 128
3

If you are using Typescript 4.1 or newer, you can utilize Recursive conditional types to create tuple types with flexible length:

type TupleOf<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]>;

which allows you to easily specify the value type and length of your tuple

type T1 = TupleOf<string, 3>;

Then such tuple would compile

const tuple: T1 = ['one', 'two', 'three'];

whereas this one wouldn't

const tuple: T1 = ['one', 'two', 'three', 'four'];
TS2322: Source has 4 element(s) but target allows only 3

The downside is of course that you can't easily specify different types in the tuple, so this approach is rather suitable for single-typed tuples.

Dan Macak
  • 16,109
  • 3
  • 26
  • 43
0

If you are using Typescript 3.1 or newer you don't need to add special limitations to tuples:

declare var a: [string, number];

You may notice that code

declare var a: [string, number];

a[0] = "1"
a[1] = 2;
a[2] = "3";
a[3] = 4;

compiles in 3.0.1 but doesn't compile in 3.1.6 with messages

Index '2' is out-of-bounds in tuple of length 2.
Index '3' is out-of-bounds in tuple of length 2.

Qwertiy
  • 19,681
  • 15
  • 61
  • 128