Strongly-typed destructuring and rest parameters
Tags: typescript, javascript, react
Published: 2019-10-30 04:33:23

---
title: Strongly-typed destructuring and rest parameters
published: true
description: Destructuring assignment and rest parameters are awesome and typical in codebases these days. Is it possible to strongly-type these though in TypeScript? Let's find out ...
tags: typescript, javascript, react
cover_image: https://www.carlrippon.com/wp-content/uploads/2019/10/ts-de-re-1024x351.png
---

Destructuring assignment and rest parameters are awesome and typical in codebases these days. Is it possible to strongly-type these though in TypeScript? Let’s find out.

## TypeScript has tuples
Before we figure out how to strongly-type rest parameters, let’s understand tuples. A tuple can be thought of as an array with a fixed number of elements. They are nice for small and obvious data structures. For example, the useState React hook returns a tuple:

```javascript
const [state, setState] = useState(initialState);
```

TypeScript lets us define tuples in a type annotation by specifying the type of each element in square brackets. For example:

```javascript
const tomScore: [string, number]: ["Tom", 70];
```

## Open-ended tuples
What have tuples got to do with rest parameters? Well, we’ll get there eventually.

TypeScript lets us have tuples where we can have a varying number of end elements like below:

```javascript
["Tom", 70]
["Jane", 70, 60]
["Fred", 70, 60, 80]
```

We can specify the type for the above example as `[string, ...number[]]`.

## Strongly-typing rest parameters

I wonder if we can use an open-ended tuple to strongly-type a rest parameter? Let’s try to do this for the scores parameter in the function below:

```javascript
function logScores(firstName, ...scores) {
  console.log(firstName, scores);
}

logScores("Ben", 50, 75, 85)  // outputs Ben and [50, 75, 85]
```

Let’s try this:

```javascript
function logScores(firstName: string, ...scores: [...number[]]) {
  console.log(firstName, scores);
}
```

If we think about it, `[...number[]]` is just `number[]`. So, this can be simplified to:

```javascript
function logScores(firstName: string, ...scores: number[]) {
  console.log(firstName, scores);
}
```

... and if we consume the function:

```javascript
logScores("Ben", 50, 75, 85)     // okay
logScores("Mike", 90, 65, "65")  // Argument of type '"65"' is not assignable to parameter of type 'number'
```

Great – it works!

## Strongly-typing destructured assignment

Specifying the type on destructured object variables is perhaps not achieved how you might first expect. The following doesn’t specify type annotations for firstName and score:

```javascript
const fred = { firstName: "Fred", score: 50 };
const { firstName: string, score: number } = fred;
```

Instead, it specifies names for the destructured variables:

```javascript
console.log(firstName);  // cannot find name 'firstName'
console.log(score);      // cannot find name 'score'
console.log(string)      // "Fred"
console.log(number)      // 50
```

We specify the type annotation after the destructured object as follows:

```javascript
const { firstName, score }: { firstName: string, score: number } = fred;
console.log(firstName);   // "Fred"
console.log(score);       // 50
```

If we are destructuring a tuple, we specify the tuple type after the destructured tuple:

```javascript
const tomScore: [string, number]: ["Tom", 70];
const [firstName, score]: [string, number]  = tomScore;
console.log(firstName);   // "Tom"
console.log(score);       // 70
```
 
We can specify a type on an open-ended tuple as follows:

```javascript
const tomScores: [string, ...number[]] = ["Tom", 70, 60, 80];
const [firstName, ...scores]: [string, ...number[]]  = tomScores;
console.log(firstName);   // "Tom"
console.log(scores);      // 70, 60, 80
```

It is worth noting that often TypeScript cleverly infers the types of destructured elements, but it is good to know how to specify type annotation in the edge cases when it doesn’t.

## Wrap up

TypeScript tuples are a convenient way of strongly-typing small and obvious data structures. Open-ended tuples can be used to strongly-type rest parameters. TypeScript generally smartly infers the types of destructured elements for us, but when it can’t, we can simply put a type annotation after the destructured items.

*Originally published at https://www.carlrippon.com/strongly-typed-destructuring-and-rest-parameters/ on Oct 29, 2019.*