When you access a deeply nested property in JavaScript, JavaScript gives an error like Cannot read property 'x' of undefined
.
That's frustrating, right? 😖
Optional chaining (?.
) solves this problem. It allows you to safely access deeply nested values without worrying about breaking your code when something in the chain is null
or undefined
.
What is Optional Chaining?
Optional chaining is a feature in JavaScript introduced in ES2020 that lets you access properties of an object without throwing an error, even if they are null
or undefined
.
Syntax:
object?.property;
object?.[expression];
object?.method?.();
If the left-hand side is null
or undefined
, it short-circuits and returns undefined
, instead of throwing an error.
Why Use Optional Chaining?
Before optional chaining, accessing deeply nested missing properties could crash your app.
const user = {};
console.log(user.address.country); // Error: Cannot read property 'country' of undefined
Now with optional chaining:
console.log(user.address?.country); // Output: undefined
Examples of Optional Chaining
Accessing a Nested Property
Without optional chaining:
const user = {
name: "Shefali",
address: {
country: "India",
},
};
console.log(user.address.country); // Output: India
console.log(user.profile.bio); // Uncaught TypeError: user.profile is undefined
With optional chaining:
const user = {
name: "Shefali",
address: {
country: "India",
},
};
console.log(user.address?.country); // Output: India
console.log(user.profile?.bio); // Output: undefined
Accessing an Array Item Safely
Without optional chaining:
const users = null;
console.log(users[0]); // Uncaught TypeError: users is null
With optional chaining:
const users = null;
console.log(users?.[0]); // Output: undefined
Calling a Method Safely
Without optional chaining:
const user = {
sayHi: () => console.log("Hello!"),
};
user.sayHi(); // Output: Hello!
user.sayBye(); // Uncaught TypeError: user.sayBye is not a function
With optional chaining:
const user = {
sayHi: () => console.log("Hello!"),
};
user.sayHi?.(); // Output: Hello!
user.sayBye?.(); // Output: undefined (no error thrown)
If the method doesn't exist, JavaScript won't throw an error, it just skips the call.
API Responses
Without optional chaining:
const apiResponse = {
data: {
user: {
profile: { name: "Shefali" },
},
},
};
console.log(apiResponse.data.user.profile.name); // Output: 'Shefali'
console.log(apiResponse.data.user.settings.theme); // Uncaught TypeError: apiResponse.data.user.settings is undefined
With optional chaining:
const apiResponse = {
data: {
user: {
profile: { name: "Shefali" },
},
},
};
console.log(apiResponse.data?.user?.profile?.name); // Output: 'Shefali'
console.log(apiResponse.data?.user?.settings?.theme); // Output: undefined
Optional Chaining with Nullish Coalescing
You can combine optional chaining with the nullish coalescing ??
operator to provide a default value.
For example:
const user = {};
const bio = user.profile?.bio ?? "No bio available!";
console.log(bio); // Output: No bio available!
If profile
or bio
doesn’t exist, it returns the fallback.
Things to Keep in Mind
- You can only use
?.
on something that might benull
orundefined
. If the object exists but the property doesn’t, it still returnsundefined
, and that's fine! - Don’t overuse it. Optional chaining is powerful, but you should still validate your data properly in most cases.