Optional Chaining
Table of Contents + −
In the previous lesson, we learned how to provide safe defaults. Now let’s learn how to safely read values from objects that might not exist, using optional chaining.
🔗 What is Optional Chaining?
The optional chaining operator ?. lets you read a property deep inside an object without causing an error if part of the path is null or undefined. Instead of crashing, it simply returns undefined.
This solves one of the most common errors beginners hit: “Cannot read property of undefined”.
💥 The Problem It Solves
Imagine a user object where the address is sometimes missing.
const user = { name: "Alex",};
console.log(user.address.city); // ❌ Error: Cannot read property 'city' of undefinedLet’s walk through why this code crashes:
- The
userobject only has aname, souser.addressisundefined. - Reading
.cityfromundefinedis not allowed, so JavaScript throws an error and stops the program.
✅ The Solution With ?.
With optional chaining, JavaScript checks each step. If address is missing, it stops and returns undefined instead of throwing an error.
const user = { name: "Alex",};
console.log(user.address?.city); // undefined → no errorHere is what each part does:
- The
?.afteraddresssays “only continue if the value before me exists”. - Since
addressis missing, JavaScript stops there and the whole expression becomesundefined, so nothing crashes.
🎯 Combining With Nullish Coalescing
Optional chaining pairs perfectly with the ?? operator from the last lesson. Use ?. to read safely, then ?? to provide a default.
const user = { name: "Alex",};
const city = user.address?.city ?? "Unknown";console.log(city); // "Unknown"Let’s read this line from left to right:
user.address?.citysafely reads the city and gives backundefinedbecauseaddressis missing.- The
??operator then sees thatundefinedand replaces it with the fallback"Unknown". - So
cityends up holding"Unknown", which we print.
A powerful pair
?. keeps your code from crashing, and ?? gives a sensible fallback. Together
they make reading uncertain data safe and clean.
📞 Optional Chaining With Functions and Arrays
You can also use ?. to call a method that might not exist, or to read an array item safely.
const user = { name: "Alex",};
// Call sayHi only if it existsuser.sayHi?.(); // does nothing, no error
// Read an array item safelyconsole.log(user.friends?.[0]); // undefined, no errorLet’s go through both safe operations:
user.sayHi?.()checks whethersayHiis a real function first; since it is missing, the call is skipped instead of throwing an error.user.friends?.[0]checks whetherfriendsexists before reading index0; since it is missing, the expression returnsundefined.- Notice the syntax: we write
?.()to call a function and?.[0]to read an array item.
⚠️ Common Mistakes to Avoid
| Mistake | Problem | Solution |
Using ?. everywhere | It can hide real bugs by silencing errors | Use it only where a value is genuinely optional |
| Forgetting the default | You get undefined instead of a useful value | Add ?? defaultValue when you need a fallback |
| Wrong syntax for arrays or calls | user.friends?.0 is invalid | Use ?.[0] for arrays and ?.() for function calls |
🔧 Try It Yourself!
- Create a
userobject with only anameproperty. - Try reading
user.address.cityand see the error. - Use
user.address?.cityand see it returnundefinedinstead. - Add
?? "Unknown"to provide a default value.
🧩 What You’ve Learned
- ✅
?.safely reads properties that might not exist - ✅ It returns
undefinedinstead of throwing an error - ✅ It prevents the common “Cannot read property of undefined” crash
- ✅ Combine
?.with??to read safely and provide a default - ✅ Use
?.()for optional function calls and?.[index]for arrays
🚀 What’s Next?
You have finished the Operators module. Next, we will start controlling which code runs using conditions, beginning with the if statement. Let’s continue to if Statement.