Optional Chaining Has Arrived!

Laurie - Dec 20 '19 - - Dev Community

Last week we talked about Nullish Coalescing, now it's time for another new addition to ECMAScript.

The dreaded existence check

Have you ever worked with an API full of objects that were inconsistently formed? Multiple levels deep and frustrating to parse. Let's use a smaller example to talk about this.

const obj = {
  node : {
    thing: 1
  }
}
Enter fullscreen mode Exit fullscreen mode

Suppose we want to access thing. We can do it like this.

const thing = obj.node.thing
Enter fullscreen mode Exit fullscreen mode

But what if we can't guarantee that node exists? If we try and access thing on undefined we'll trigger an error. So we'll have to check first.

const thing = obj.node ? obj.node.thing : undefined
Enter fullscreen mode Exit fullscreen mode

This is the terser option, using a ternary, but it works all the same.

This is a reasonable piece of code! But it can get incredibly repetitive if you have deeply nested objects.

Optional Chaining to the Rescue

Well, we don't have to do that anymore. We can use the new optional chaining syntax.

const thing = obj.node?.thing
Enter fullscreen mode Exit fullscreen mode

In this case, obj.node is undefined. Typically, trying to access thing on undefined would trigger an error, but not in this case! When you use optional chaining it doesn't throw that error and instead evaluates the expression to undefined.

And what's even cooler is that we can combine this with nullish coalescing.

const obj = {}

const thing = obj.node?.thing ?? 2
// thing will be 2
Enter fullscreen mode Exit fullscreen mode

Since using optional chaining gives us undefined, thing will resolve to the value on the right-hand side of the ?? operator. In this case, that's 2.

Chaining Optional Chaining

Note that my example above uses optional chaining once in order to clarify how it works. However, you can use it multiple times in the same expression.

const thing = obj?.node?.thing
Enter fullscreen mode Exit fullscreen mode

The expression above is valid and may come in handy if obj looks like this.

const obj = null
Enter fullscreen mode Exit fullscreen mode

The risks

Now I can't write about optional chaining without including a section on warnings. To be honest, a lot of people were really against adding this to the language. They had concerns about abuse, and that's fair!

?. should NOT replace all instances of .. If you do that you'll create all kinds of silent failures. Optional chaining is another tool in your belt, that's it.

If you don't control the data you're accessing and it's particularly nested and it's ok if the result doesn't exist then maybe optional chaining is the right choice! But notice all those "and"s in the previous run-on sentence. Make sure you explicitly choose to use this syntax. It shouldn't be your default.

Not just for objects!

Oh, I forgot to mention the best part. Optional chaining works on more than just objects!

It works on arrays.

const tenthItem = arr?.[10]
Enter fullscreen mode Exit fullscreen mode

This makes sure that arr exists before trying to access the 10th element.

It works for function calls.

const message = obj?.stringFunction()
Enter fullscreen mode Exit fullscreen mode

This makes sure obj exists before you try and call a function on it.

And it works with top-level objects.

functionDoesNotExist?.()
Enter fullscreen mode Exit fullscreen mode

If this function doesn't exist, it will evaluate to undefined.

Isn't this fun?

So much power! But remember, that means you have a responsibility to use it wisely!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .