Optional Chaining & Nullish Coalescing
debt(d3/e1/b1/t5)
Closest to 'default linter catches the common case' (d3). ESLint and TypeScript (both listed in detection_hints.tools) automatically flag unsafe property access chains and missing optional chaining. However, the distinction between ?. and && chains isn't universally caught by default configs, so detection requires some linter tuning rather than instant compiler error.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix directly states replacing verbose null checks (user && user.address && user.address.city) with optional chaining (user?.address?.city) is a single-line substitution. No architectural change or multi-file refactor needed.
Closest to 'minimal commitment' (b1). Optional chaining is a pure syntax feature with no structural consequences. It applies locally to individual property accesses; once a developer learns the syntax, it imposes no ongoing tax on the codebase or future maintainers. It's a naming/syntax convention choice, not a system-wide commitment.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly documents the trap: ?? is not the same as ||. The common mistake list reinforces this (using || when ?? is correct for 0 and false values). This is a well-documented gotcha that catches developers switching from other languages or unfamiliar with nullish coalescing semantics, but it's discoverable through code review and testing.
Also Known As
TL;DR
Explanation
Optional chaining (obj?.prop, obj?.method(), arr?.[0]) returns undefined instead of throwing TypeError when accessing properties on null or undefined. Nullish coalescing (??) returns the right operand only when the left is null or undefined — unlike || which also triggers for 0, '', and false. Together they handle optional API response properties, default values, and deep object access safely without nested ternaries or &&-chains.
Common Misconception
Why It Matters
Common Mistakes
- Using || for defaults when 0 or false are valid values — use ?? instead.
- Not combining ?. with ?? for deep access with a fallback: user?.address?.city ?? 'Unknown'.
- Using ?. on every access in a chain when only the first link can be null — unnecessary and misleading.
- Not using ?.() for optional method calls: user.formatter?.() instead of user.formatter && user.formatter().
Code Examples
// || replaces valid falsy values:
const port = config.port || 3000; // port = 0 → uses 3000 (bug!)
const name = user.name || 'Anonymous'; // name = '' → uses 'Anonymous' (maybe wrong)
// Verbose null guards:
const city = user && user.address && user.address.city;
// ?? only replaces null/undefined:
const port = config.port ?? 3000; // port = 0 → keeps 0
const name = user.name ?? 'Anonymous'; // name = '' → keeps ''
// Optional chaining + nullish coalescing:
const city = user?.address?.city ?? 'Unknown';
const len = data?.items?.length ?? 0;