Pdf Processor
Nullish coalescing and logical OR cannot be mixed without parens
TLDR
We wrotemeta?.pageCount ?? pageSections.size || null in a pipeline change, and the build failed with a parse error that had nothing to do with types or logic. ECMAScript forbids mixing the nullish coalescing operator ?? with || or && in one expression without parentheses. The editor and the type checker stayed silent. The bundler was the first thing to complain. meta?.pageCount ?? (pageSections.size || null) fixed it, and the precedence question is now answered explicitly instead of by convention.
| Expression | Result |
|---|---|
meta.pageCount ?? size | |
meta.pageCount ?? (size |
Bug class
Nullish coalescing does not compose with the logical operators. The grammar bans a ?? b || c and a ?? b && c outright, because the two operators answer different questions, "is this nullish?" versus "is this falsy?", and mixing them is ambiguous.
The trap is that the failure arrives late. The expression parses in our heads as "coalesce, then fall back". The engine refuses to guess. The editor did not underline it, the type checker saw no type error, because the problem is not a type problem. The code is simply illegal.
Our bundler said it plainly:
[eval]:1
const a = 1; const b = null; const c = a ?? b || 0;
^^
Nullish coalescing operator(??) requires parens when mixing with logical operators
SyntaxError: Unexpected token '||'
// DEFECTIVE: this threw at build time
const pageCount = meta?.pageCount ?? pageSections.size || null;
// FIXED: explicit grouping states the intent
const pageCount = meta?.pageCount ?? (pageSections.size || null);
The fix is one pair of parentheses. The lesson is larger. With ??, precedence is not a style question. It is a legality question.
How to prevent the class
- Parenthesize every expression that combines
??with||or&&, whether you think you need to or not. - Add an ESLint rule such as
no-mixed-operatorswithallowSamePrecedence: false, so a static error replaces a build-time error. - Treat the build step as a safety net, not the primary check. If a parse error sits unnoticed until the bundler runs, your feedback loop is too long.
The generalizable lesson
When a language feature is illegal in combination, the fix is never "remember the rule". It is to encode the rule in a lint rule or in parentheses. The cheap fix today prevents the identical failure next month, when the expression has been copy-pasted into a different context.
Read this post in the full Engineering Journal →