Skip to content

core-bugs-loose-equality

CategoryDefault severityLifecycleDefault confidence
bugMINORexperimental0.95 (clamped to 0.6 while experimental)

What it catches

Loose-equality operators == and != in TypeScript / JavaScript source. Strict-equality === / !== is what the author almost always meant. String literals and comments are stripped before matching so docs that mention the operators don't fire.

Why it matters

JavaScript's loose-equality coercion produces a famously long list of surprising truths:

  • 0 == '0'true
  • '' == 0true
  • [] == falsetrue
  • null == undefinedtrue
  • [1] == 1true

Each == in production code is a potential bug waiting on the right input shape. The fix is mechanical (add one =), so leaving the rule unflagged is pure technical debt. AI-generated code reaches for == at a much higher rate than modern human-written code under common style guides — flagging it surfaces a systemic gap, not one-off mistakes.

Example: failing code

export function isReady(state: unknown): boolean {
  return state == 'ready';                 // MINOR
}
export function hasItems(arr: unknown): boolean {
  if (arr == null) return false;           // MINOR — see "intentional null check" below
  return Array.isArray(arr) && arr.length != 0;
}

Example: how to fix

export function isReady(state: unknown): boolean {
  return state === 'ready';
}
export function hasItems(arr: unknown): boolean {
  if (arr === null || arr === undefined) return false;
  return Array.isArray(arr) && arr.length !== 0;
}

The "I really do want null OR undefined" case

This is the one legitimate use of ==. Two equally clear alternatives:

// Explicit:
if (x === null || x === undefined) { ... }

// Nullish-coalescing where appropriate:
const v = x ?? defaultValue;

Both are catchable by the next maintainer without remembering JavaScript coercion rules.

Known limitations

  • Doesn't flag Object.is(a, b) vs a === b (different semantic, only relevant for NaN / -0).
  • JSX expressions inside {...} use the same operator rules — the rule fires on those too, which is intended.

Suppression

If you really need the loose-equality semantic on one line:

// codemore-ignore-next-line: core-bugs-loose-equality
if (x == null) return defaultValue;

Or for an entire file:

/* codemore-ignore-file: core-bugs-loose-equality */

References

Next →
Back to the catalog
See the other 57 rules — grouped by pack, with lifecycle gates.