Special kind of array in Typescript - Tuple
Tags: javascript, webdev, typescript, react
Published: 2021-09-26 03:27:25

In strictly typed programming languages, `array` is a Data structure of `homogeneous data types` with `fixed length`. In contrast **JavaScript** is dynamic. In here,  `array` can have elements of `heterogeneous  data type` and `length` can vary. 

**In JavaScript:** 

```js 
const elements = ['rick', 23, false];

const len = elements.length; // len = 3

elements.push({name: 'morty'}); 

const changedLen = elements.length; // changedLen = 4
```

With **Typescript**, we can restrict that and force arrays to have `homogeneous data type` what I mean is this. 

**In Typescript:**

```ts
const elements: string[] = ['rick', 'morty'];

const len = elements.length; // len = 2
```

Now if we try to push `number` or any other data type other than `string` in `elements` then Typescript will yell at us. 

```ts
const elements: string[] = ['rick', 'morty'];

elements.push(1) // Error
/**
* Error: Argument of type 'number' is not assignable to 
* parameter of type 'string'.
*
*/
```
Even though Typescript enforces the type but `length` is still not fixed. We can push another element of type `string` in `elements` array. 

```ts
const elements: string[] = ['rick', 'morty'];

const len = elements.length; // len = 2

elements.push('summer')

const changedLen = elements.length; // changedLen = 3
```

**What if our requirement changes like this:** 

##Requirement 1: 

* An `Array` with type `number`, `boolean` and `string` only. 

**Solution**

Well! that is easy, we can use `union` type with `array` in Typescript like this: 

```ts
const elements: Array<number|boolean|string> = ['summer'];

elements.push(23); // ok
elements.push(true); // ok 

console.log(elements) // ["summer", 23, true] 

elements.push({name: 'morty'}) // Not OK : Error
/**
* Error: Argument of type '{ name: string; }' is not 
* assignable to parameter of type 'string | number | 
* boolean'.
*/
```

One point to note here is: 

> The sequence of the `data type` is not fixed as we defined during the declaration. What it means that, we can push `number`, `boolean` and `string` in any order. 

For example, This is also perfectly valid and OK with TypeScript: 

```ts 
const elements: Array<number|boolean|string> = [true];

elements.push(23); // ok
elements.push('summer'); // ok 

console.log(elements) // [true, 23, "summer"] 
```

By `Array<number|boolean|string>`, we only narrowed the type and told Typescript that this collection should only have elements of type  `number`, `boolean` and `string`. The order can be anything. Typescript do not mind as long as the type is one of the declared types.

##Requirement 2 : 

* An array with a fixed number of items
* `type` of elements are fixed at each index
* The `type` of elements need not be same at all the index

What did you just say **An array with a fixed number items** ?? 

![loki-wtf](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqifxrinaq20c01mbjvi.gif)
 
And it can have different type at different index? oh okkkk......

![oh-okay-simpsons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1dhim6g2hb8dshcbyt7.gif)

**Solution**

Actually this is possible with new `type` called `tuple` in `Typescript`. 

##Tuple - Special kind of Array

As per [official docs](https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple): 

> Tuple types allow you to express an array with a fixed number of elements whose types are known, but need not be the same.
 
Tuple fulfils all the requirements described above. Let's see how can we define a `tuple`. 

```ts
/**
* let's define a info of character id, name and activeStatus
*/
 const info: [number, string, boolean] = [33, 'Rick' , true];

```
* **An array with a fixed number items**

Just by doing this, now we fixed number of elements in `info` i.e. `3`. So now if you try to access the element at index `4` Typescript will yell at you. 


```ts  
 const info: [number, string, boolean] = [33, 'Rick' , true];

const item = info[4] // error
/**
* Tuple type '[number, string, boolean]' of length '3' has no 
* element at index '4'.
*/

// In contrast if we declare an array with union type like
// below, it will be ok to access the element at index 4 

const arr: Array<number|string|boolean>
                 = [33, 'Rick' , true];
const arrItem = arr[4] //undefined
```

* **Type of elements are fixed at each index**

By defining `[number, string, boolean]`, we have fixed the type of elements at each index. Typescript will infer the type from `tuple`. 


```ts
 const info: [number, string, boolean] = [33, 'Rick' , true];
 const item1 = info[0] // type number
 const item2 = info[1] // type string
 const item3 = info[2] // type boolean
 
 // In contrast, array with union type 

const info: Array<number| string| boolean>
                 = [33, 'Rick' , true];

// type of items can be either string, number or boolean

 const item1 = info[0] // type string | number | boolean
 const item2 = info[1] // type string | number | boolean
 const item3 = info[2] // type string | number | boolean

```
Advantage of doing this is, I can get all the methods available to `string` for `item2`. 

![Screenshot 2021-09-25 at 1.25.58 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkna54t194cooctlcxtm.png)

* **The `type` of elements need not be same at all the index**

The type of elements in tuple can be same as well as different: 

```ts
const a: [number, string, boolean] = [33, 'Rick' , true];
const b: [string, string, string] = ['Mr', 'Rick' , 'alive'];
```

## Practical example: 

You might be thinking, it looks great but where do we use it. 

One of the examples that I can think of is in our custom hooks where we have to return an array consisting values of different data type. Take for example `useToggle` custom hook 

```ts 
import { useCallback, useState } from "react";

export const useToggle = (
  intialValue: boolean = false
): [boolean, () => void] => {
  const [state, setState] = useState(intialValue);

  const setToggle = useCallback(
       () => setState((flag) => !flag), 
   []);

  return [state, setToggle];
};
```

Here we have to return `current status` of `toggle` and a `function to change the status`. That's why, the return type is a tuple `[boolean, () => void]`. 


If we simply return an array, and assign the second argument i.e. setter function to `onClick`, Typescript will throw a compile time error as the return type is union of `boolean` and `() => void` . 

```ts
Type 'boolean | (() => void)' is not assignable to type 

'((event: MouseEvent<HTMLButtonElement, MouseEvent>) 
    => void) 
   | undefined'.
```

![Screenshot 2021-09-25 at 1.59.21 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o00p73hya1wqqn0gva78.png)

You can checkout these examples here: 

{% codesandbox usetoggle-46itn %}

Thank you for reading.
 
##Read my other TypeScript articles 

* [Unknown and any type in Typescript](https://dev.to/thejsdeveloper/world-of-any-and-unknown-in-typescript-29cd)

Follow me on [twitter](https://twitter.com/VikasYadav_Dev)

##References

* [Official Docs](https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple)
* [auth0 Tuple article](https://auth0.com/blog/typescript-3-exploring-tuples-the-unknown-type/)