Write more reliable JavaScript with optional chaining
Let me know if this sounds familiar: you’re deep into debugging or trying to access a deeply nested property in a JavaScript object. Suddenly you see this classic error:
TypeError: Cannot read property 'x' of undefined
It happens a lot with API responses, optional fields, and dynamic data.
JavaScript has a fix for this: optional chaining (?.). It’s saved me from more than a few headaches, and I’d bet it’ll do the same for you.
The problem with deep property access
Let’s start with this snippet of code:
if (user && user.profile && user.profile.avatar) {
console.log(user.profile.avatar);
}
This pattern might look familiar. We’re checking each level of the object to avoid accessing a property of undefined or null. It’s verbose, and it’s easy to get wrong, especially in large codebases where object shapes change often.
Hello, optional chaining
Optional chaining (?.) gives you a shorter, safer way to read nested properties:
console.log(user?.profile?.avatar);
If user or profile is null or undefined, JavaScript short-circuits the evaluation and returns undefined without throwing an error. Optional chaining keeps your code brief and easier to follow.
Real-world use cases
Here are a few places it comes in handy:
Accessing API response data
const name = response?.data?.user?.name;
If one of the intermediate objects isn’t there, you don’t get a runtime error.
Safely accessing DOM elements
const value = document.querySelector("#myInput")?.value;
If the element doesn’t exist, value will just be undefined.
Optional method calls
user?.sendMessage?.("Hello!");
This ensures that user exists and that sendMessage is a function before attempting to call it. Otherwise, it simply returns undefined.
In frameworks (React, Redux, etc.)
Optional chaining is especially helpful in component-based libraries like React:
const title = props?.article?.data?.attributes?.title;
When props may be undefined during initial renders, this prevents crashes and keeps your components stable.
Optional chaining vs. logical AND (&&)
Before optional chaining, a common pattern used looked like this:
const avatar = user && user.profile && user.profile.avatar;
It works, but it’s more verbose and harder to maintain. Optional chaining simplifies this:
const avatar = user?.profile?.avatar;
It reads better and makes the intent clearer. Also, remember: && checks for truthiness, while ?. short-circuits only on null or undefined.
Side-by-side comparison
Common patterns before and after optional chaining:
| Before | After |
|---|---|
user && user.name |
user?.name |
user && user.getName && user.getName() |
user?.getName?.() |
arr && arr[0] |
arr?.[0] |
fn && fn() |
fn?.() |
document && document.querySelector("#el") |
document?.querySelector("#el") |
Limitations and gotchas
Optional chaining isn’t magic. A few caveats:
- It only short-circuits if the value before
?.isnullorundefined. Other falsy values (false,0,"", etc.) still proceed to the next property. - Optional chaining doesn’t prevent passing
undefineddeeper into your logic. If you aren’t careful, you might mask a bug. - Overuse can hide underlying issues or suggest your data structures need clarification.
Specific gotcha
Be careful:
user?.profile.avatar
This only guards against user being null or undefined. It still tries to access avatar directly from profile, so if profile is undefined, this will still throw an error.
Instead use:
user?.profile?.avatar
Optional chaining with arrays
const firstItem = myArray?.[0];
This prevents an error if myArray is undefined.
Combine with nullish coalescing (??)
Want to provide a default value if the property is missing? Combine optional chaining with the nullish coalescing (??) operator:
const avatar = user?.profile?.avatar ?? "default.png";
This returns "default.png" if avatar is null or undefined.
Browser support
Optional chaining is supported in all modern browsers (Chrome 80+, Firefox 74+, Safari 13.1+, Edge 80+), but not in Internet Explorer. Use a transpiler like @babel/plugin-proposal-optional-chaining if you need compatibility with legacy browsers.
Try it out
Optional chaining cuts a lot of boilerplate and the “cannot read property of undefined” errors that come with it. If you have code full of && chains or manual undefined guards, try swapping a few out and see how it reads.