ESC

Type to search the knowledge base.

Nullish Coalescing

Use ?? for null/undefined defaults without treating 0 or empty string as missing — vs ||, ??= and optional chaining.

beginner3 min read
  • javascript
  • nullish-coalescing

|| as a default operator is a classic footgun: it treats all falsy values as missing. ?? (nullish coalescing) only falls through for null and undefined.

const count = input || 10;
// input = 0  → 10  (wrong if 0 is valid)

const count2 = input ?? 10;
// input = 0  → 0
// input = null → 10

Semantics

a ?? b
// If a is null or undefined, result is b; otherwise a.
// b is not evaluated if a is non-nullish (short-circuit).
Left left || right left ?? right
0 right 0
'' right ''
false right false
null right right
undefined right right
'hi' 'hi' 'hi'

With optional chaining

const theme = user?.settings?.theme ?? 'system';
// missing chain → undefined → 'system'

?. stops on nullish and yields undefined; ?? supplies the default. They pair constantly in real UI code.

Assignment: ??=

options.timeout ??= 5000;
// assign only if options.timeout is null or undefined
// does not overwrite 0

Same family: ||=, &&= with falsy/truthy rules instead of nullish.

Precedence gotcha

// SyntaxError without parens in some mixes with && / ||
// const x = a ?? b || c;  // illegal in JS
const x = (a ?? b) || c;
const y = a ?? (b || c);

The language forbids mixing ?? with &&/|| without parentheses so you state intent.

When || is still right

You want empty string / 0 / false to mean “use default”:

const label = (title || 'Untitled').trim();
// blank title → Untitled

That’s a product choice, not a language mistake — just don’t use || for numeric configs.

Defaults vs function parameters

function connect({ host = 'localhost', port = 8080 } = {}) {
  // param defaults also only replace undefined, not null
}
connect({ port: null }); // port is null inside — not 8080
// if null should default:
function connect2({ port } = {}) {
  const p = port ?? 8080;
}

Interview answer (out loud)

“?? returns the right side only when the left is null or undefined, so valid falsy values like 0 and empty string are kept. || collapses all falsy. Combine with ?. for nested access, use ??= for assign-if-nullish, and parenthesize if you mix with && or ||.”

Chaining nullish

const v = a ?? b ?? c ?? 'fallback';

Left-associative: first non-nullish wins. Combine with optional chaining carefully:

const port = opts?.server?.port ?? 8080;

React props defaults

function Avatar({ size, url }) {
  const px = size ?? 40;
  // vs default params: function Avatar({ size = 40 })
  // default params also only replace undefined, not null
}

If a parent passes size={null} meaning “use default,” you need ?? in the body, not only default params.

Further reading

Related guides