Nullish Coalescing (??) & Logical Assignment
debt(d3/e1/b1/t5)
Closest to 'default linter catches the common case' (d3). ESLint and TypeScript can detect || used where ?? is more appropriate (code_pattern explicitly mentions this), catching the most common mistake automatically.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix is explicit: replace || with ??. This is a mechanical substitution that requires no refactoring, no parameter changes, and no cross-file coordination.
Closest to 'minimal commitment' (b1). This is pure syntax choice—a naming convention for 'how to write default values'—with no load-bearing or cross-cutting implications. Once a team adopts ?? for defaults, every future maintainer simply writes new code the same way. No component is shaped by the choice.
Closest to 'notable trap' (t5). The misconception ('?? and || are interchangeable') is the canonical gotcha. Developers with || muscle memory from other languages will assume both behave the same way; many do eventually learn the distinction. The common_mistakes confirm this is documented and expected to trip people up, but it's not a catastrophic misunderstanding—once explained, the logic is sound.
Also Known As
TL;DR
Explanation
?? (ES2020) vs ||: ?? only checks null/undefined; || checks all falsy values (0, '', false, NaN). For API responses with 0 counts or empty strings, ?? prevents incorrect fallbacks. Logical assignment: ??= assigns only if null/undefined, ||= only if falsy, &&= only if truthy. PHP's ?? operator has the same semantics as JS ??. Optional chaining ?. accesses deeply nested properties safely without null checks.
Common Misconception
Why It Matters
Common Mistakes
- Using || for default values when 0 or empty string are valid response values
- Confusing ?. (optional chaining) with ?? (nullish coalescing)
- ??= not well-supported before 2021
Code Examples
// || incorrectly overrides valid 0 count:
const count = apiResponse.count || 0; // If count is 0, stays 0... wait no: 0 || 0 = 0
const label = apiResponse.label || 'Default'; // If label is '' — uses 'Default' incorrectly
// PHP parallel that also has this bug:
// $label = $response['label'] ?: 'Default'; // '' triggers fallback
// ?? only falls back on null/undefined:
const count = apiResponse.count ?? 0; // 0 count preserved
const label = apiResponse.label ?? 'Default'; // '' label preserved
// Optional chaining + nullish coalescing:
const city = user?.address?.city ?? 'Unknown';
// Logical assignment — lazy initialise:
cache[key] ??= expensiveCompute(key);
// PHP parallel:
// $city = $user['address']['city'] ?? 'Unknown';