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