
Safer Property Access with Optional Chaining and Nullish Coalescing
Reading deeply nested properties from asynchronous API responses or optional configuration objects has historically required verbose && guard chains to prevent TypeError: Cannot read property of undefined. Worse yet, pairing those lookups with the logical OR operator (||) to assign default values silently overwrites valid falsy values such as 0, false, or "".
Having reached Stage 4 for inclusion in ES2020, the optional chaining operator (?.) and the nullish coalescing operator (??) work together to make nested property access concise and bug-free. Optional chaining short-circuits to undefined as soon as a reference is null or undefined, while nullish coalescing only falls back when the left-hand side is strictly null or undefined.
Example
// Legacy guard chain + buggy || fallback when animationMs is 0
var duration =
config && config.ui && config.ui.animationMs
? config.ui.animationMs
: 250;
// ES2020 Optional Chaining (?.) + Nullish Coalescing (??)
const duration = config?.ui?.animationMs ?? 250;
Input : Deeply nested configuration or API object where intermediate properties may be missing or set to 0
Output : Safe property lookup that preserves intentional 0, false, and "" values without throwing runtime errors.
Implementation
const userResponse = {
id: 402,
profile: {
displayName: "Elena Rostova",
preferences: {
itemsPerPage: 0,
theme: ""
}
},
getNotificationUrl: null
};
function normalizeUserSettings(payload) {
// 1. Deep property access safely short-circuits if profile or address is missing
const city = payload?.profile?.address?.city ?? "Remote";
// 2. Nullish coalescing preserves 0 instead of replacing it with 20
const pageSize = payload?.profile?.preferences?.itemsPerPage ?? 20;
// 3. Preserves empty string "" if explicitly set, unlike logical OR (||)
const theme = payload?.profile?.preferences?.theme ?? "light";
// 4. Optional method invocation only executes if getNotificationUrl is a function
const webhook = payload?.getNotificationUrl?.() ?? "/api/notifications/default";
return {
city,
pageSize,
theme,
webhook
};
}
console.log(normalizeUserSettings(userResponse));
// {
// city: "Remote",
// pageSize: 0,
// theme: "",
// webhook: "/api/notifications/default"
// }
Main Point: Replace || default assignments with ?? whenever 0, false, or "" are valid domain values, and use ?. to traverse optional object trees, bracket keys (obj?.[key]), and optional callbacks (fn?.()).
Credits
Photo by Shahadat Shemul