Tuples are ok
Tags: typescript, javascript, webdev
Published: 2020-03-28 14:23:53

--- series: It is ok ---
There are opinions in the community that Tuple types should not be used ever. There are movements also against functions arguments, and using one dictionary/map argument instead. As with all radical opinions, saying that we should not use tuples is wrong. We should, but not for everything, in the same way there is no ideal data structure, tuple has limited correct scope of use.

{% twitter 1243835195217895425 %}
## What is Tuple
Tuple type represents ordered list of fixed size, and fixed type of elements. The most common tuple is a pair, so tuple with 2 elements. For example we can represent a point by a pair `[number, number]` in TS notation.

## Functions arguments list is a tuple
If you have a function, its arguments form a tuple, so for example lets consider simple `move` function which will move the point.
```ts
// [TS]
declare function move(x: number, y: number): void
move(1,2);
// equivalent to
declare function move(...[x, y]: [number, number]): void
move(1,2)
```
## Tuple is isomorphic to Map
Tuple and Map/Dictionary are example of [Product types](https://dev.to/macsikora/algebraic-structures-explained-part-1-base-definitions-2576#product-type) and are isomorphic. Isomorphism means that from every tuple we can make a map, and from every map we can make a tuple. The proof is simple transformation in boths direction.
```ts
// [TS]
type TuplePoint = [number, number];
type MapPoint = {x: number, y: number};
// below transformations in both directions
function toTuple({x,y}: MapPoint) {
  return [x,y]
}
function toMap([x,y]: TuplePoint) {
  return {x, y}
}
```

## When to use Tuple
Tuples are great if small. It means that there is no issue in using double or triple tuples. The question starts at quadruple, for me it is a moment when it can work well, but also it can start to be a problem. But to be clear, I believe there can exists great use for longer tuples, however I would be careful with such.

Good examples of using tuples are points, dimensions like (x,y), (width, height), (x,y,z), also almost all pairs, like (name, lastname), (symbol, translation) and so on. Because of destructuring (destructuring exist in most languages with tuples - JS/TS, Python, Elm, Reason, Haskell) and possibility of naming elements of the tuple, there is also no issue in readability. Consider comparison function taking two arguments (a pair), and function taking one labelled argument.
```ts
// [TS]
function fullName(name, lastName) {
  return name.concat(lastName);
}
fullName("John", "Doe");
// in contrary version with map
function fullName({name, lastName}) {
  return name.concat(lastName);
}
fullName({name: "John", lastName: "Doe"}) // more boilerplate
```

## React useState as a great usage of the Tuple type
React hook `useState` is returning a tuple. The reason why tuple is the best choice here is the polymorphism of `useState`. We really use the same function to represent different states, so also the naming should be different. JS destructuring feature allows for local aliasing tuple structures.
```js
// [JS]
const [name, setName] = useState("");
const [lastname, setLastName] = useState("");
const [age, setAge] = useState(0);
```
In contrary how it would look if React team would use map instead:
```js
// [JS]
const {value: name, setValue: setName} = useState("");
const {value: lastName, setValue: setLastName} = useState("");
const {value: age, setValue: setAge} = useState(0);
```
Better? Don't think so 😉.

> To be fair we could be doing with map `const nameState = useState(""); nameState.setValue("Tom");` What is kinda ok.

## When to not use tuples
As said before, tuples are great when small. Long tuples can be a pain, the biggest reason is that with longer tuple its harder to remember at which position stands which thing, we can fix that in TypeScript by aliasing types, but this is an additional thing to do. So I would rather think twice before using longer tuple.

The bad using of the tuple
```ts
// [TS]
type User = [string, string, number, bool]; // yhym, so what is second string?
// we can fix that by aliasing
type Name = string;
type Lastname = string;
type Age = string;
type Active = boolean;
type LittleBetterUser = [Name, LastName, Age, Active] // yhym now I get it
// but map will work best here
type UserAsMap = {
  name: string,
  lastname: string,
  age: number,
  active: boolean
}
```
**BTW**, do you remember that functions with many arguments are consider as a bad practice? As we already said function arguments list is a tuple, and using long tuple can be a burden, in the same way functions with many arguments can be considered as a problem.

## Summary
Tuple is a very nice structure, used wisely should be considered as alternative for small structs/maps. Don't be radical and give Tuple some love ❤.