The optional chaining operator (?.
) allows us to safely access properties and methods of objects when the object that has the property may be null
or undefined
.
This avoids the need to write multiple conditional checks to ensure that each level of the access chain is defined.
Before the introduction of the optional chaining operator in JavaScript, we had to manually check if each property existed before attempting to access the next one.
The ?.
operator is very useful and greatly simplifies our code (and you know, simpler is more readable and maintainable).
Basic Syntax
The basic syntax of the optional chaining operator is as follows:
const result = object?.property;
In this case,
- If
object
has a defined value, it will accessproperty
normally. - If
object
isnull
orundefined
,result
will beundefined
and no error will be thrown.
Let’s look at a practical example to better understand how the optional chaining operator works:
let user = {
name: 'Luis',
address: 'A beautiful house'
};
let postalCode = user?.address?.postalCode;
let barcode = user?.product?.barcode;
console.log(postalCode); // Result: '12345'
In this example,
- We access the
address
property of theuser
object. - Since this property exists, we will get the value ‘A beautiful house’.
On the other hand,
- We also access
product.barcode
(which does not exist) - However, instead of throwing an exception, we simply get
undefined
.
Multiple Chaining
The optional chaining operator can also be used with multiple chaining. This allows us to make “safe chains”.
let result = object?.property1?.subproperty?.subsubproperty;
For example,
const user = {
profile: {
address: {
city: 'Madrid'
}
}
};
const city = user.profile?.address?.city;
console.log(city); // 'Madrid'
If user.profile
or user.profile.address
were null
or undefined
, city
would be undefined
, avoiding an error when trying to access a property of an undefined object.
Usage with Methods
The optional chaining operator can also be used to invoke methods that might not be defined:
const result = object?.method?.();
Here, if object
or method
are null
or undefined
, no error will be thrown and result
will be undefined
. If both are defined, method
will be invoked.
For example,
const person = {
name: 'Ana',
greet: () => 'Hello'
};
const greeting = person.greet?.();
console.log(greeting); // 'Hello'
If person.greet
were null
or undefined
, it would not attempt to invoke the method and greeting
would be undefined
.
Accessing Array Elements
Although less common, the optional chaining operator can also be used to access elements of arrays:
const users = [{ name: 'Carlos' }, null, { name: 'Sofia' }];
const firstName = users[0]?.name;
const secondName = users[1]?.name;
const thirdName = users[2]?.name;
console.log(firstName); // 'Carlos'
console.log(secondName); // undefined
console.log(thirdName); // 'Sofia'
Combination with Nullish Coalescing Operator ??
The optional chaining operator can be combined with the nullish coalescing operator (??
) to provide default values:
const user = {};
const name = user.profile?.name ?? 'Default name';
console.log(name); // 'Default name'
Here, name
will be 'Default name'
if user.profile
is undefined
or null
.
Comparison with Other Access Techniques
Using &&
Conditions
Before optional chaining, it was common to use &&
conditions to avoid access errors in nested objects:
const city = user && user.profile && user.profile.address && user.profile.address.city;
This approach is less readable and more error-prone. The optional chaining operator simplifies this syntax:
const city = user?.profile?.address?.city;
Avoid using &&
for this. It’s terrible. Use ?.
, that’s what it’s for 😉
Using Ternary Operator
The ternary operator can also be used to check if intermediate levels are defined:
const city = user ? (user.profile ? (user.profile.address ? user.profile.address.city : undefined) : undefined) : undefined;
However, this method no one can read that is more complex and less readable compared to the optional chaining operator.
Don’t do that! 😆
Limitations of the Optional Chaining Operator
Does Not Prevent Assignments
The optional chaining operator cannot be used for assignments. It can only be used to access properties and methods:
object?.property = value; // This will generate an error
Does Not Detect All Errors
Optional chaining only avoids errors related to an undefined property or method. It does not handle other types of errors that may arise when accessing properties or methods:
const result = object?.method()?.property;
That is, if calling method()
causes your program to crash, ?.
does not protect you from that (it does not handle exceptions, it’s not a try-catch).