What is optional chaining in JavaScript, and why is it used?
Optional chaining (?.) is a feature in JavaScript that allows you to safely access deeply nested properties, methods, or array elements without having to check if each level exists manually.
If the value before ?. is null or undefined, it short-circuits and returns undefined instead of throwing a runtime error (Cannot read property of undefined). Remember, it is only for reading properties or calling functions.
Use cases of optional chaining:
1. Prevent runtime errors when dealing with uncertain or optional data (like API responses).
2. Reduce boilerplate code with multiple && checks.
3. Make code cleaner, safer, and more readable.
Case-wise Examples:
- Object Property Access
const user = {
profile: { name: "Abid" }
};
// Traditional way
console.log(user && user.profile && user.profile.name); // "Abid"
// With optional chaining
console.log(user?.profile?.name); // "Abid"
console.log(user?.address?.city); // undefined (no error)2. Function/Method Calls
const user = {
greet: () => "Hello!"
};
console.log(user.greet?.()); // "Hello!"
console.log(user.sayHi?.()); // undefined (no error)3. Array Access
const users = [{ name: "Abid" }, null];
console.log(users[0]?.name); // "Abid"
console.log(users[1]?.name); // undefined
console.log(users[2]?.name); // undefined4. Dynamic Property Access
const user = {
profile: { age: 26 }
};
const key = "age";
console.log(user?.profile?.[key]); // 26
console.log(user?.settings?.[key]); // undefined5. Chaining with API Responses (real-world)
const apiResponse = {
data: {
user: {
address: { city: "Dhaka" }
}
}
};
// Without optional chaining (ugly & error-prone)
console.log(
apiResponse &&
apiResponse.data &&
apiResponse.data.user &&
apiResponse.data.user.address &&
apiResponse.data.user.address.city
);
// With optional chaining
console.log(apiResponse?.data?.user?.address?.city); // "Dhaka"In a Word, “Optional chaining (?.) is used in JavaScript to safely access properties, methods, or array elements that might not exist, avoiding runtime errors and reducing repetitive null checks. It improves readability and is especially useful when handling optional or uncertain data, such as API responses.”
The limitations / Gotchas of Optional Chaining
- Cannot be used on the left-hand side of an assignment
const user = {};
// user?.name = "Abid"; // ❌ SyntaxError
// Correct way
if (user) user.name = "Abid";
// Optional chaining only works for reading properties, not writing to them.2. Only checks for null or undefined
const obj = { value: 0, flag: false };
// These are valid and will NOT trigger optional chaining
console.log(obj?.value); // 0
console.log(obj?.flag); // false
// Optional chaining does not guard against falsy values like 0, "", or false. Only null or undefined.3. Cannot use with ++ / — / = operators directly
const user = {};
// user?.count++; // ❌ SyntaxError4. May hide errors you want to catch
const obj = {};
console.log(obj?.nonExistent.prop); // undefined
// Problem: You might expect an error if a property is truly missing
// Optional chaining can silently hide mistakes if overused. Use it where missing values are expected, not for debugging logic errors.5. Combining with nullish coalescing
Optional chaining is often paired with ?? to provide defaults:
const user = {};
console.log(user?.name ?? "Guest"); // "Guest"
// This is safe and very common in API responses.In short, Optional chaining is extremely useful for safely accessing nested data, but it only works for reading, not writing. It only checks for null or undefined, so falsy values like 0 or false are returned as-is. Overusing it might hide logical errors, so it’s best used where data is genuinely optional, like API responses.”
Optional Chaining — Interview Q&A
1️⃣ What is optional chaining (?.) in JavaScript?
👉🏻 Optional chaining (?.) allows you to safely access nested object properties, methods, or array elements without manually checking for null or undefined. If the value before ?. is null or undefined, it returns undefined instead of throwing an error.
Get Abid Hasan’s stories in your inbox
Join Medium for free to get updates from this writer.
2️⃣ Why is optional chaining used?
👉🏻 It is used to:
1. Avoid runtime errors when accessing deeply nested properties.
2. Reduce boilerplate code with multiple null checks.
3. Safely handle uncertain or optional data, like API responses.
3️⃣ How does optional chaining differ from using && for checking properties?
👉🏻
const name = user && user.profile && user.profile.name; // old way
const name = user?.profile?.name; // optional chaining
// Optional chaining is cleaner, readable, and shorter.
// Both return undefined if a property is missing.4️⃣ Can optional chaining be used for function calls?
👉🏻 Yes. It can safely call functions that may not exist:
user.greet?.(); // calls greet if it exists, else returns undefined5️⃣ Can optional chaining be used for arrays?
👉🏻 Yes, you can safely access array elements:
const arr = [{name:"Abid"}, null];
console.log(arr[1]?.name); // undefined6️⃣ Can optional chaining be used to assign a value?
👉🏻No. Optional chaining cannot be used on the left-hand side of an assignment:
user?.name = "Abid"; // ❌ SyntaxError
// It is only for reading properties or calling functions.7️⃣ Does optional chaining protect against falsy values like 0 or false?
👉🏻 No. Optional chaining only checks for null or undefined.
const obj = { value: 0, flag: false };
console.log(obj?.value); // 0
console.log(obj?.flag); // false8️⃣ Can optional chaining hide errors in your code?
👉🏻 Yes. Overusing it may silently hide bugs if you expect a property to exist but it doesn’t. Use it when missing data is expected, like API responses.
9️⃣ How can optional chaining be combined with nullish coalescing (??)?
👉🏻 We can provide default values for missing properties:
const username = user?.name ?? "Guest";
console.log(username); // "Guest"🔟 Give a real-world example of using optional chaining.
👉🏻
const apiResponse = {
data: { user: { address: { city: "Dhaka" } } }
};
console.log(apiResponse?.data?.user?.address?.city); // "Dhaka"
console.log(apiResponse?.data?.user?.phone?.number); // undefined
// TypeError: Cannot read property 'number' of undefined
// but
console.log(apiResponse.data.user.phone.number); // TypeError: Cannot read property 'number' of undefined







