What is optional chaining in JavaScript?

We will get a runtime error when we try to access an object property that is not present.

let user =  {
 name : "Anitha",
}

user.info.age;

In the above code, when we try to access user.info.age, we will get an error because info is not preset in the user object; so, info is undefined. When we try to perform some operation on undefined or null, we get an error.

To solve the issue in the code above, check if the property exists:

let user =  {
 name : "Anitha",
}

// using conditional operator 

let age = user.info ? ( user.info ? user.info.age : undefined) : undefined

// using && operator 
age = user.info && user.info.age;

The above problem can be solved neatly with the new optional chaining operator.

Optional chaining (?.)

The ?. operator is used to check and access the property of an object; if an intermediate property is undefined or null, then undefined is returned.

let user =  {
 name : "Anitha",
}

user?.info?.age; // undefined is returned.

In this line, user?.info?.age:

user?

  • will check if the user object is undefined or null.

.info

  • if the user object is undefined or null, then undefined is returned
  • if the user object is not undefined or null, then its info property is accessed

info?

  • checks if info is valid (not undefined or null).

.age

  • if info is valid, then age is accessed
  • Otherwise, undefined is returned
user?.info?.age

// the above code is equal to 
user && user.info && user.info.age 
// or 
user ? (user.info? user.info.age : undefined) : undefined;

Checking the value of unknown keys

We can use the [] operator if we don’t know the key name.

let user = {
  info : {
     name : "Anitha"
  }
};
function getVal(obj, key1, key2) {

  return obj?.[key1]?.[key2]; // [key1] - runtime key name evaluation 

}
getVal(user, 'info', 'name');

Calling a function with the ?. operator

let user = {
  info : {
     name : "Anitha",
     print(){
      console.log(this.name);
     }
  }
};
user.info?.print?.(); // Anitha

In the code above, we checked if the print property is available in user.info. If the print property is available, then it will be called.

We don’t use ?. on an object that we know will be present anyway.

let user = {
  info : {
     name : "Anitha",
     print(){
      console.log(this.name);
     }
  }
};
// instead of 
user?.info?.print?.();

// use 
user.info?.print?.(); 

If we know info will be present in all user objects, then we don’t use ?. on user?.. Instead, use it with the info property, like user.info?..

Deleting a property using ?.

let user = {
   name : "Anitha",
   age : 25
}
console.log(user); // {name: "Anitha", age: 25}

delete user?.name; // check if the name property exists and deletes it 

console.log(user); // {age:25}

We can use the ?. operator to read and delete values, but not to assign values.

let user = {}

user?.info = {}; //SyntaxError: Invalid left-hand side in assignment

Using ?. with a short circuit operator

let user = {}
let x = 0;
user?.increment?.(++x); 
x; // 0

If the property before ?. is undefined or null, then the right part is skipped, so that the short circuit operator will not be executed in the above code.

Recap

  • obj?.prop will return prop if obj exists; otherwise, it returns undefined
  • obj?.[propName] is equal to obj[propName]
  • obj?.func?.() will execute func if the method func exists
  • delete obj?.prop deletes the prop if the obj exists