Clean Markup

Safer Property Access with Optional Chaining and Nullish Coalescing

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

← Home