Tuple Types

Typing tuple-like array values

Tuples are a sort of list but with a limited set of items. In JavaScript, tuples are created using arrays.

In Flow you can create tuples using the [type, type, type] syntax.

1
2
3
let tuple1: [number] = [1];
let tuple2: [number, boolean] = [1, true];
let tuple3: [number, boolean, string] = [1, true, "three"];

When you are getting a value from a tuple at a specific index, it will return the type at that index.

1
2
3
4
5
6
// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

let num  : number  = tuple[0]; // Works!
let bool : boolean = tuple[1]; // Works!
let str  : string  = tuple[2]; // Works!

If you try getting from an index that does not exist it will return a type of void.

1
2
3
4
// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

let none: void = tuple[3];
Cannot get `tuple[3]` because tuple type [1] only has 3 elements, so index 3 is out of bounds.

If Flow doesn’t know which index you are trying to access it will return all possible types.

1
2
3
4
5
6
7
// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

function getItem(n: number) {
  let val: number | boolean | string = tuple[n];
  // ...
}

When setting a new value inside a tuple, the new value must match the type at that index.

1
2
3
4
5
6
7
8
9
10
11
12
13
// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

tuple[0] = 2;     // Works!
tuple[1] = false; // Works!
tuple[2] = "foo"; // Works!

// $ExpectError
tuple[0] = "bar"; // Error!
// $ExpectError
tuple[1] = 42;    // Error!
// $ExpectError
tuple[2] = false; // Error!
Cannot assign `"bar"` to `tuple[0]` because string [1] is incompatible with number [2]. Cannot assign `42` to `tuple[1]` because number [1] is incompatible with boolean [2]. Cannot assign `false` to `tuple[2]` because boolean [1] is incompatible with string [2].

Strictly enforced tuple length (arity)

The length of the tuple is known as the “arity”. The length of a tuple is strictly enforced in Flow.

Tuples only match tuples with same length

This means that a shorter tuple can’t be used in place of a longer one.

1
2
3
4
// @flow
let tuple1: [number, boolean]       = [1, true];
// $ExpectError
let tuple2: [number, boolean, void] = tuple1; // Error!
Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 2 but tuple type [2] has an arity of 3.

Also, a longer tuple can’t be used in place of a shorter one.

1
2
3
4
// @flow
let tuple1: [number, boolean, void] = [1, true];
// $ExpectError
let tuple2: [number, boolean]       = tuple1; // Error!
Cannot assign array literal to `tuple1` because array literal [1] has an arity of 2 but tuple type [2] has an arity of 3. Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 3 but tuple type [2] has an arity of 2.
Tuples don’t match array types

Since Flow does not know the length of an array, an Array<T> type cannot be passed into a tuple.

1
2
3
4
// @flow
let array: Array<number>    = [1, 2];
// $ExpectError
let tuple: [number, number] = array; // Error!
Cannot assign `array` to `tuple` because array type [1] has an unknown number of elements, so is incompatible with tuple type [2].

Also a tuple type cannot be passed into to an Array<T> type, since then you could mutate the tuple in an unsafe way.

1
2
3
4
// @flow
let tuple: [number, number] = [1, 2];
// $ExpectError
let array: Array<number>    = tuple; // Error!
Cannot assign `tuple` to `array` because tuple type [1] is incompatible with array type [2].
Cannot use mutating array methods on tuples

You cannot use Array.prototype methods that mutate the tuple, only ones that do not.

1
2
3
4
5
// @flow
let tuple: [number, number] = [1, 2];
tuple.join(', '); // Works!
// $ExpectError
tuple.push(3);    // Error!
Cannot call `tuple.push` because property `push` is missing in `$ReadOnlyArray` [1].

Was this guide helpful? Let us know by sending a message to @flowtype.