domains / app-frameworks / Expressjs/Express
Strict null checks
Many reported bugs stemmed from using generic truthy/falsy checks (`!x`, `x || y`, ternaries) when the real intent was to detect "missing" (`null`/`undefined`) values. Falsy-but-valid values such as `''`, `0`, `false`, or `'0'` were incorrectly treated as absent, causing logic errors (e.g. an empty `X-Forwarded-Host` header being overwritten, or a `'0'`...
Many reported bugs stemmed from using generic truthy/falsy checks (!x, x || y, ternaries) when the real intent was to detect “missing” (null/undefined) values. Falsy-but-valid values such as '', 0, false, or '0' were incorrectly treated as absent, causing logic errors (e.g. an empty X-Forwarded-Host header being overwritten, or a '0' response body losing its Content-Length).
Apply these rules when handling nullable/optional values:
- Use explicit comparisons (
=== undefined,=== null, orx == nullto cover both) instead of!xorx || ywhen a falsy-but-valid value must be preserved. - Prefer the nullish coalescing operator/assignment (
??,??=) for defaulting, since it only falls back onnull/undefinedand leaves other falsy values intact:// Bad: overwrites valid falsy values (e.g. `etag: false`) opts.etag = opts.etag || this.app.enabled('etag'); // Good: only applies default when unset opts.etag ??= this.app.enabled('etag'); - Remember that
typeof x === 'object'istruefornull; always guard separately:if (options && typeof options === 'object') { ... } - When distinguishing “header/option not provided” from “provided but empty”, use
typeof x === 'undefined'orx === undefinedrather than a truthy check, and document why:// '' is a valid but falsy value; only fall back when truly unset if (typeof host === 'undefined') { host = this.get('Host'); } - Avoid coercing unknown/null/undefined inputs into stringified placeholders (e.g.
String(null)->"null"); validate the type explicitly and throw or handle the nullable case intentionally rather than silently producing misleading output. - When spreading a potentially-undefined object, no fallback is needed (
{ ...maybeUndefined }safely yields{}), so don’t add redundant|| {}guards.
Following these patterns prevents silent data corruption, keeps optional/nullable handling predictable, and makes the intent of each null/undefined check explicit to future readers.</description>