Optional Chaining in JavaScript (?.)

Image by Jordan Hopkins.

If you've worked with JavaScript before, you know how frustrating it can be to handle nested object properties, especially if you're trying to keep your code DRY, succinct, and optimised.

Rather than returning undefined or null when an access continues through a value that is null or undefined, JavaScript throws an error. A missing final property by itself evaluates to undefined; the error occurs when code then tries to read another property from that value. Without optional chaining, each uncertain level needs a guard before access continues.

Some example code that came up recently during a code review. I should be clear: I do not recommend this, and I'll explain why further down the page...

const model = car && car.manufacturer  ? car.manufacturer.model  : null;

Not to repeat myself, but please don't do this.


What's the Problem?

The example I've been working on most recently aggregates music data, so that seems like a good basis for my examples.

Let's say we're working with a music listing site. Each artist has a listing page that just displays albums with their tracklists and cover art. For each album, we put together a JavaScript object which contains all the necessary information. We can't always trust that our content team will have entered all of the information correctly, though!

So, to grab the source of the album cover, we might start off with something like this:

console.log(album.coverArt.url);

This is a risky way to access your album art because JavaScript will throw an error if the coverArt property isn't set. We can mitigate this scenario by using an if statement (like the code review snippet I included earlier). I'm going to use longform if statements rather than shorthand here, just because it's more illustrative of what we're doing:

if (album.coverArt) {  console.log(album.coverArt.url);}

As a singlelevel check, this isn't too bad but it would be handy if we didn't need that if statement. This quickly becomes more complex though; what if our coverArt object had multiple URLs for example for different image sizes?

if (album.coverArt) {  if (album.coverArt.url) {    console.warn(album.coverArt.url.thumbnail);  }}

This starts to look a lot like the car manufacturer ternary function I keep referring back to. This is messy, and this still is not an especially complex example.

What if we had a user object, with things like addresses? We would have to chain if statements all the way down. Aside from being a huge waste of space, this becomes repetitive and unwieldy very quickly...


Optional Chaining ‑ the Solution

Thankfully as part of the ES2020 spec JavaScript has introduced a syntax that can solve this issue for us. Quite simply, you replace . with ?.. Add it at each uncertain access in the chain rather than replacing dots mechanically. Using this, we can condense the chain of if statements down into an effective shorthand, like this:

console.log(album?.coverArt?.url?.thumbnail);

This won't throw an error, even if the coverArt property isn't present. It will return undefined. Each ?. checks only the value immediately to its left for null or undefined, which is why every uncertain link in the example has its own operator.

What makes this even cooler and discussed far less in my experience is that we can also use this operator with methods and the square bracket syntax too. Following on from our music platform example, what if our product had a deal which meant that some artist pages used affiliate links? In our instance, this was delivered via an aged backend system and a function. This meant that we would have to first check whether the function existed for that specific artist:

album.affiliateLinkClick?.()

This will trigger and run the affiliateLinkClick function if it exists, and otherwise simply won't do anything aside from return undefined. If the property exists but is not callable, the optional call still throws a TypeError.

This optional chaining syntax will hopefully help you cut down on repeated code or wasted characters in your work and it helps to keep your code clear and easy to read, too.


Need a senior engineer involved?

I can work directly in the codebase, review the architecture, or support the team through delivery when the work needs more than extra hands.