The optional chaining operator ?.
is used to access the properties and methods of an object safely. If any of the intermediate properties in the chain is null
or undefined
, it stops evaluating the expression and returns undefined
, rather than throwing an error.
What problem does it solve?
We often have an error that says TypeError: Cannot read properties of undefined
when we access the properties of an object that is null or undefined.
Example:
const user = {
name: "Peter"
};
console.log(user.address.country);// TypeError: Cannot read properties of undefined
In the above example, the user
object doesn't have an address
property. The value of the address
property is undefined
, and we are accessing the country
property on undefined
. So, the compiler throws the error TypeError: Cannot read properties of undefined
.
A traditional way to handle this type of error is to use a conditional check:
// we only access country property if address property exists on user object
if(user && user.address){
console.log(user.address.country);
}
But this solution becomes verbose when an object has many levels of nesting:
const user = {
name:"Peter",
address: {
country:{
name: "US",
countryCode: "+1"
}
}
}
if(user && user.address && user.address.country){
console.log(user.address.country.countryCode);
}
We can see in the above example that our code looks verbose and complex.
Use ?.
to avoid complex conditional check
The optional chaining operator ?.
makes our code easy to read and less verbose.
We don't have to check whether a property exists on an object. As soon as the optional operator (?.
) encounter an undefined
or null
in chaining, it stops immediately and returns undefined
.
const user = {
name: "Peter"
};
// if user exists, then access address, if address exists, then access country
console.log(user?.address?.country);// undefined
We can see that we don't have to conditionally check if the address
property exists on the user
object.
The expression user?.address?.country
can be read as: if the user
exists then access address
property, and if the address
property exists then access country
property.
Even if the object has many nested levels, our code looks easy to read and less verbose.
const user = {
name:"Peter",
address: {
country:{
name: "US",
countryCode: "+1"
}
}
}
// less verbose and easy to read
console.log(user?.address?.country?.countryCode); // "+1"
Optional chaining is not valid on the left-hand side of an assignment
The optional chaining parameter(?.) can't be used on the left side of an assignment, it will throw an error Uncaught SyntaxError
.
let user = {};
user?.name = "Peter";// Uncaught SyntaxError: Invalid left-hand side in assignment
Optional chaining with function calls
We can also check whether a method exists on an object.
const user = {
getName(){
console.log("Peter");
}
}
user.getName?.(); // Peter
user.getAge?.(); // undefined
Optional chaining with an array
let arr;
console.log(arr[2]);//Error:Cannot read properties of undefined
console.log(arr?.[2]);// undefined
Conclusion
The optional chaining operator makes our code more readable and less verbose. And it also prevents throwing the error TypeError: Cannot read properties of undefined
.
I hope you get to learn something from this blog. Thanks for reading the article.