DEV Community

Manav Misra
Manav Misra

Posted on

Optional Chaining ⛓️

Before we start to understand optional chaining, we should understand undefined and what the motivation behind optional chaining is.

undefined

const me = {
  name: "CodeFinity",
  age: 300, 
}

console.log(me.handles); // undefined
Enter fullscreen mode Exit fullscreen mode

With our composite data types - collections such as object literals 👆🏽 - if access a 🔑 that doesn't exist we get back a special primitive data type, undefined.

Yea, it's a bit weird that JS has its own 'special data type' and even weirder that we have yet another primitive data type, null (we'll deal with that in the next post in this series).

Nevertheless, hopefully at this point you can accept that the handles is a key that has 'no definition' within the context of me👆🏽.

At this point, JS is not 'error-ing out' - it's 🙆🏽‍♂️ with undefined
Now, referencing me 👆🏽 once again, what if we did: console.log(me.handles.twitter)

Uncaught TypeError: Cannot read property 'twitter' of undefined

Observations

  1. Accessing a 🔑 within an object literal that doesn't exist is 🙆🏽‍♂️ - it's undefined.
  2. Accessing a 🔑 on something that is undefined is 🙅🏽‍♂️ - it creates an error❗

undefined is its own primitive data type. It's not a collection type. Therefore anytime that we invoke . on undefined, JS is going to have a problem with that. By definition, primitive data types are discrete values; they cannot hold any 🔑s! That's what that error message is telling us 👆🏽.

Preventing Our Program From Crashing 😑

Referencing again, the attempt to access: me.handles.twitter 👆🏽, without optional chaining, I might have to write my code like this one:

// Referencing 'me' 👆🏽

if (me.handles) {
  console.log(me.handles.twitter)
}
Enter fullscreen mode Exit fullscreen mode

Now, my program will not crash because we will never reach the line: console.log(me.handles.twitter).

Instead, JS will apply implicit coercion to: me.handles. This just means that since we are using if, 'under the hood,' JS will look at the undefined value that stems from me.handles and will 'coerce' it to false (it's a 'false-y' value). So, that code inside of the { after that if will not run.

Short-Circuit && Approach

We could also do this by _short circuiting &&: me.handles && console.log(me.handles.twitter).

This time, when me.handles gets' implicitly coerced to false the right-hand side operand of && will never get run 🍦.

Ternary Approach

We could also shorten that code by using a ternary:

// Referencing 'me' 👆🏽

console.log(me.handles ? me.handles.twitter : "");
Enter fullscreen mode Exit fullscreen mode

JS would again, implicitly coerce me.handles to false and would take the right hand side operand of the : operator, "", thereby logging that empty string.

Use Optional Chaining - ?. - to Prevent Our Program From Crashing 🤓

console.log(me.handles?.twitter)

This syntax sort of applies the ternary, but in a simpler way. That . after ? is the 'optional' part of this.

First, we are asking the a ❓, "Hey, JS, does me.handles come back as an object literal?" If so, then go ahead with this next part of my chain. If not, please don't freak out 😱...let's just leave it as undefined and move on.

Examples

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah'
  }
};

const dogName = adventurer.dog?.name;
console.log(dogName);
// expected output: undefined

console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined
Enter fullscreen mode Exit fullscreen mode

Yes, this works for methods also: console.log(adventurer.someNonExistentMethod?.());

Here's another example from that same MDN link (slightly modified):

const customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls" // detailed address is unknown
  }
};

const customerCity = customer.details?.address?.city;
Enter fullscreen mode Exit fullscreen mode

From this one, we see that we can chain optional chaining.

⚠️

I should mention that optional chaining is an ES2020 thing. This means that unless you are using something like Babel as part of your build process, you will probably not be able to use this feature in your code today. For example, a Node.js repl.it will freak out about this. However, Chrome Dev Tool's console can use optional chaining.

Top comments (0)