Making Friends With Optional Chaining in TypeScript
Tags: typescript, javascript, esnext
Published: 2019-10-15 07:30:21

---
title: "Making Friends With Optional Chaining in TypeScript"
published: true
description: "Nested property access can be tricky in JavaScript, leading to long chains of &&. Learn how to use optional chaining for cleaning up your code."
tags: typescript, javascript, esnext
canonical_url: https://www.valentinog.com/blog/chaining/
---

Originally published on [my blog](https://www.valentinog.com/blog/chaining/).

To be honest I never jump on newest JavaScript proposals so fast. If it's not at least at stage 3 most of the times I gloss over. But if the new feature is implemented in TypeScript then I know it's going to be good.

That's exactly the case with **optional chaining in TypeScript**. It will land into JavaScript and it's already available in TypeScript beta.

## Setting up TypeScript

First things first create a new project and install TypeScript beta:

```bash
mkdir optional_chaining_ts && cd $_

npm init -y

npm i typescript@beta
```

Next up generate a configuration file for TypeScript:

```bash
node_modules/typescript/bin/tsc --init
```

Once done create a new JavaScript file and name it as you wish, I called mine **optional_chaining.js**. And now let's see optional chaining in action.

## The problem: map function and undefined

From now on we'll work inside **optional_chaining.js**. Suppose you've got the following array:

```javascript
const arr = [
  { code: "a" },
  { code: "b" },
  { code: "c" },
  { name: "Caty" },
  { name: "Siri" }
];
```

You want to loop over it to produce a new array containing only those objects with the **code** property. The map function is your friend and we can do:

```javascript
const arr = [
  { code: "a" },
  { code: "b" },
  { code: "c" },
  { name: "Caty" },
  { name: "Siri" }
];

const withCode = arr.map(function(element) {
  if (element.code) return element;
});
```

The only problem now is that we get **undefined** for every element where map couldn't find the **code** property. Here's the resulting array:

```text
// withCode now is
[ { code: 'a' },
  { code: 'b' },
  { code: 'c' },
  undefined,
  undefined ]
```

At this point **in JavaScript you would be free to access an empty index**, or worst, a **non-existing object**:

```javascript
const notThere = withCode[3].code;
```

Only at **runtime your program will throw** (or your [JavaScript test suite](https://www.valentinog.com/blog/jest/) will fail if you tested that edge case):

```text
TypeError: Cannot read property 'code' of undefined
```

The problem exists more in general with **property access on nested objects**. Consider another example:

```javascript
const people = { mary: { name: "Mary" } };

const caty = people.caty.name;

// TypeError: Cannot read property 'name' of undefined
```

What can be done to **protect our code** from these kind of errors? Let's see if **TypeScript can help**.

## The solution: TypeScript and optional chaining

Let's get TypeScript to check our code. Rename **optional_chaining.js** to **optional_chaining.ts**. Then try to compile:

```bash
node_modules/typescript/bin/tsc
```

You should see the following error:

```text
optional-chaining.ts:13:18 - error TS2532: Object is possibly 'undefined'.

13 const notThere = withCode[3].code;
                    ~~~~~~~~~~~
```

Good catch TypeScript! How did you know? TypeScript sees that the statement **if (element.code) return element;** could exclude objects whose properties don't have "code". And that will lead to undefined elements.

At this point we have **two options**. We can return an empty object like { name:"empty" } as a fallback from the map function. But it could be bad for performance. **Better, we could check if our object exists before** accessing a key:

```javascript
const notThere = withCode[3] && withCode[3].code;
```

What a hacky thing to do right? How many times did you see code like that? We had no choices until now.

With **optional chaining** instead we can **clean up the code** and reduce the check to:

```javascript
const notThere = withCode[3]?.code;
```

If you followed along you should have this code (I've added a console log for printing notThere):

```javascript
const arr = [
  { code: "a" },
  { code: "b" },
  { code: "c" },
  { name: "Caty" },
  { name: "Siri" }
];

const withCode = arr.map(function(element) {
  if (element.code) return element;
});

const notThere = withCode[3]?.code;

console.log(notThere);
```

You can call it a day and go home now, but **keep reading if you're interested in the nitty-gritty**.

## Optional chaining in TypeScript: how does it compiles?

Save, close the file and compile/run:

```bash
node_modules/typescript/bin/tsc

node optional-chaining.js
```

and you should see "undefined" in the console. Still an empty value, but at least the code doesn't throw at runtime. How did we end up with "undefined" by the way?

TypeScript takes the new syntax:

```javascript
const notThere = withCode[3]?.code;
```

and **compiles down** to (assuming you're compiling to ECMAScript 2009):

```javascript
"use strict";

var _a;
// omit
var notThere = (_a = withCode[3]) === null || _a === void 0 ? void 0 : _a.code;

console.log(notThere);
```

Notice in particular these line of code:

```javascript
var _a;
var notThere = (_a = withCode[3]) === null || _a === void 0 ? void 0 : _a.code;
```

We can **deconstruct them to plain english**. The left part of the expression (**before ||**) works like so:

**Assign withCode[3] to the variable _a** (declared in the head). Now check if _a is equal to null. If not, evaluate the right side of the **logical or**.

Not let's focus on the right edge of the expression (**after ||**). 

It's a **ternary operator** stuffed with two [void operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void). The expression **void 0 produces the undefined primitive**. You can read the code like so:

**If _a is equal to undefined, then return undefined, otherwise return _a.code**.

In other words **optional chaining always returns undefined when the value we're trying to access is non-existent**, and **property access on objects won't throw**.

## Wrapping up

JavaScript moves at a fast pace and so **TypeScript**, which pushes new feature and innovations forwards into the language. **Optional chaining** aims to simplify one of the most common patterns in JavaScript: **nested property access on objects**.

With optional chaining we can avoid TypeError in situations like the following:

```javascript
const people = { mary: { name: "Mary" } };

const caty = people.caty.name;

// TypeError: Cannot read property 'name' of undefined
```

The same code with optional chaining becomes:

```javascript
const people = { mary: { name: "Mary" } };

const caty = people.caty?.name;

// Instead of 
// const caty = people.caty && people.caty.name;
```

Thanks for reading and stay tuned.

## Resources

New to TypeScript? Learn more with [TypeScript Tutorial For Beginners: The Missing Guide](https://www.valentinog.com/blog/typescript/).

More on optional chaining [here](https://github.com/tc39/proposal-optional-chaining).