Skip to main content

no-constant-binary-expression

Comparisons that always evaluate to true or false, and logical expressions that either always short-circuit or never short-circuit, are usually programmer errors.
Rule Type: Problem
Fixable: No

Why This Rule Exists

These errors are especially common in complex expressions where operator precedence is easy to misjudge:
// This looks like: a + (b ?? c)
const x = a + b ?? c;

// But it actually evaluates as: (a + b) ?? c
// Since a + b can never be null, the ?? c has no effect!
Also, comparing newly constructed objects by reference will always be false, which can surprise developers from other languages:
// This always returns false (objects compared by reference)
const isEmpty = x === [];

Rule Details

This rule identifies:
  • == and === comparisons that always evaluate to true or false
  • ||, &&, and ?? expressions that always or never short-circuit

Examples

Incorrect Code

// Unary plus always produces a number, never null
const value1 = +x == null;

// Empty object is always truthy, so || DEFAULT never runs
const value2 = condition ? x : {} || DEFAULT;

// !foo is boolean, never null
const value3 = !foo == null;

// new Boolean creates an object, never === true
const value4 = new Boolean(foo) === true;

// Comparing with newly constructed object (always false)
const objIsEmpty = someObj === {};
const arrIsEmpty = someArr === [];

// Always short-circuits at false
const shortCircuit1 = condition1 && false && condition2;

// Always short-circuits at true
const shortCircuit2 = condition1 || true || condition2;

// Always short-circuits at "non-nullish"
const shortCircuit3 = condition1 ?? "non-nullish" ?? condition2;

Correct Code

// Check x directly for null
const value1 = x == null;

// Parenthesize to make intent clear
const value2 = (condition ? x : {}) || DEFAULT;

// Negate the comparison, not the value
const value3 = !(foo == null);

// Use Boolean function (not constructor)
const value4 = Boolean(foo) === true;

// Check actual emptiness
const objIsEmpty = Object.keys(someObj).length === 0;
const arrIsEmpty = someArr.length === 0;

// Conditions that can actually vary
const shortCircuit1 = condition1 && condition2;
const shortCircuit2 = condition1 || condition2;
const shortCircuit3 = condition1 ?? condition2;

Common Patterns

Object/Array Comparisons

In JavaScript, objects are compared by reference, not by value. A new object never equals any other value.
// Wrong: Always false
if (user === {}) { }
if (arr === []) { }
if (regex === /test/) { }

// Right: Check properties or length
if (Object.keys(user).length === 0) { }
if (arr.length === 0) { }

Type Coercion Issues

// Wrong: Unary + converts to number, never null
if (+value == null) { }

// Right: Check before converting
if (value == null) { }
if (isNaN(+value)) { }

Operator Precedence

// Wrong: && has higher precedence than ||
const result = a || b && c; // Means: a || (b && c)

// Wrong: + has higher precedence than ??
const value = a + b ?? c; // Means: (a + b) ?? c

// Right: Use parentheses for clarity
const result = (a || b) && c;
const value = a + (b ?? c);

Constructor vs Function

// Wrong: Constructor creates object, not boolean
const value = new Boolean(foo) === true;
const value = new Number(x) === 0;
const value = new String(s) === "";

// Right: Use function form
const value = Boolean(foo) === true;
const value = Number(x) === 0;
const value = String(s) === "";

// Even better: Use simple comparison
const value = !!foo;
const value = x === 0;
const value = s === "";

When Not to Use It

This rule has no legitimate use cases for disabling - constant expressions are always mistakes. If you need to disable it for a specific line, you may have found a false positive bug in ESLint.

Further Reading