A user chooses zero retries, yet the application still retries three times. The expression retries || 3 may be the culprit: it treats zero as a reason to use the fallback. When values such as zero or false are meaningful, defaults must preserve their business meaning.
1. Missing differs from falsy
The MDN ?? reference explains that the right operand is used only for null or undefined. By contrast, || falls back for any falsy value, including zero, false and an empty string.
const settings = { retries: 0, enabled: false };
console.log(settings.retries || 3); // 3
console.log(settings.retries ?? 3); // 0
console.log(settings.enabled ?? true); // false
Comments show expected results. This scenario defines zero as no retries and false as deliberately disabled. If those values are invalid for your product, validate them explicitly instead of relying on fallback operators.
2. Define policy per field
| Value | Policy question |
|---|---|
| Zero retries | Is disabling retries a valid choice? |
| An empty label | Does it mean no label or unfinished input? |
| null | Is data missing or deliberately cleared? |
Do not mechanically replace every || with ??. Some fields intentionally fall back for empty strings; others must preserve them. Document the decision before changing code.
3. Defaults are not type validation
function normalizeRetries(value) {
const retries = value ?? 3;
if (!Number.isInteger(retries) || retries < 0 || retries > 10) {
throw new TypeError('Expected an integer from 0 to 10');
}
return retries;
}
This illustrative policy defaults missing values to three and requires supplied values to be integers from zero to ten. It rejects "3", false and NaN. Ten is a product-specific example, not a universal limit.
Avoid arbitrary coercion merely to pass validation. Form fields or environment variables may contain strings and require an explicit parsing step first.
4. Keep expressions readable
Do not mix ?? directly with || or && without parentheses. Parentheses fix syntax, not policy correctness. For several fallback layers, introduce descriptive variables so reviewers can understand the priority.
The right side of ?? runs only when needed. If it calls a function, do not rely on that function's side effects for mandatory work.
5. Test checklist
- Test undefined, null, zero, false and an empty string separately.
- Test correctly typed values outside the allowed range.
- Check string input from APIs or forms.
- Ensure defaults preserve deliberate disabled settings.
- Add regression tests for missing-versus-zero mistakes.
The correct operator expresses the intended policy. Use ?? when only null and undefined require a fallback, and keep validation as a separate step.




No comments yet. Be the first to share your thoughts.