Introduced in ES2020, optional chaining allows access to properties in an object in JavaScript in a safe manner. Using the optional chaining operator (?), one can check within nested objects the value of a property without having to check whether every single reference that is in the chain is either undefined
or null
. If any of the references are found to be either undefined
or null
, the operator will perform a ‘short circuit’ and undefined
will be returned instead of throwing an error. The rest of the expression to the right of the optional chain operator is not evaluated.
Examples:
Objects
const userObj = {
firstName: 'Tom',
lastName: 'Jones',
preferences: {
theme: 'dark',
rememberLogin: true,
}
};
const userTheme = userObj.preferences.theme?;
console.log(userTheme); //dark
In the line above, we are trying to retrieve the user’s preferred theme. Using the optional chaining operator (?), we check whether the theme property exists in the nested object preferences
. Once that exists, it will retrieve the value of the theme property.
Only use optional chaining when checking the existence of something that is optional. In the example above, we only used the optional chaining operator on the theme property, since its existence is optional. The existence of both a user object (userObj
) and a preferences
object nested within the user object are required.
console.log(user?.color) //ReferenceError: user is not defined
As you can see above, if we simply try to retrieve the color property on an undeclared object called user
with the optional chaining operator, we will get a ReferenceError
. In this case, whether the optional chaining operator was used or not, the same message will be returned because the user object is undeclared.
Functions
We can also use optional chaining with functions. If the function cannot be found, undefined
is returned rather than an exception being thrown.
class User {
greetUser (name) {
return `Hello ${name}`;
};
}
let user = new User();
console.log(user.greeUser.('Tom')) //TypeError: user.greeUser is not a function
console.log(user.greeUser?.('Tom')) //undefined
console.log(user.greetUser?.('Tom')) //Hello Tom
Optional chaining with nullish coalescing
We can combine optional chaining with nullish coalescing like so:
const employee = {
firstName: 'John',
lastName: 'Smith',
profile: {
position: 'Engineering Manager'
}
}
const employeeDepartment = employee?.profile.department ?? 'Not Available';
//OR another way
const employeeDepartment = employee?.['profile' + 'department'] ?? 'Not Available';
console.log(employeeDepartment); //Not Available
Using optional chaining with arrays
We can also use optional chaining with arrays:
const array = [1, 5, 7, 3, 2, 9, 8, 0, 6];
console.log(array?.[3]); //3
console.log(array?.[20]); //undefined
Optional chaining and writing to an object property
You cannot use optional chaining in order to write to an object property. It can only be used for reading and deleting.
const employee = {
firstName: 'John',
lastName: 'Smith',
profile: {
position: 'Engineering Manager'
}
}
let assignDepartment = employee?.profile.department = 'IT'; //SyntaxError: invalid assignment left-hand side
//Delete the position
delete employee?.profile.position; //True
console.log(employee); // Object {
firstName: 'John',
lastName: 'Smith',
profile: Object {}
}