oxc-project/oxc · error
Unexpected comparison of two newly constructed objects
Error message
Unexpected comparison of two newly constructed objects
What it means
Diagnostic from `no-constant-binary-expression`, emitted by `constant_both_always_new` (crates/oxc_linter/src/rules/eslint/no_constant_binary_expression.rs:103). It fires on loose equality/inequality (`==`/`!=`) where BOTH operands are always-new references — e.g. `[a] == [a]`, `({}) == []`. Because each side constructs a distinct object, even loose equality (which never crosses two object references) is guaranteed false; the help text reads 'These two values can never be equal'.
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_constant_binary_expression.rs:104
.with_label(span)
}
fn constant_binary_operand(left_or_right: &str, operator: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected constant binary expression")
.with_help(format!(
"This compares constantly with the {left_or_right}-hand side of the {operator}"
))
.with_label(span)
}
fn constant_always_new(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected comparison to newly constructed object")
.with_help("These two values can never be equal")
.with_label(span)
}
fn constant_both_always_new(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected comparison of two newly constructed objects")
.with_help("These two values can never be equal")
.with_label(span)
}
fn constant_relational_comparison(operator: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unexpected constant relational comparison")
.with_help(format!("Both sides of the {operator} are literal values"))
.with_label(span)
}
impl Rule for NoConstantBinaryExpression {
fn from_configuration(value: serde_json::Value) -> Result<Self, serde_json::error::Error> {
DefaultRuleConfig::<Self>::from_value(value).map(DefaultRuleConfig::into_inner)
}
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::LogicalExpression(expr) => match expr.operator {View on GitHub (pinned to e1e7af627c)
Solutions
- Use a deep-equality helper: `assert.deepStrictEqual(a, b)` or `isEqual(a, b)`.
- Compare stable primitive keys (ids, serialized forms) instead of constructed objects.
- Hoist the shared object to a constant and compare references to that constant if identity is meant.
- Delete the comparison when both sides are provably the same fresh construction — it always returns false.
Example fix
// before
if ([a, b] == [a, b]) { /* never true */ }
// after
if (a === a && b === b) { }
// or, for real content checks:
if (isEqual(left, right)) { } Defensive patterns
Strategy: type-guard
Validate before calling
// Gate: loose equality between two constructed literals
const bothFresh = /(\[[^\]]*\]|\{[^}]*\})\s*=={1,2}\s*(\[[^\]]*\]|\{[^}]*\})/.test(src); Type guard
// Say what you mean: content equality
import { isEqual } from 'lodash-es';
const sameContent = (a, b) => isEqual(a, b); Prevention
- Treat `==` between two object-ish literals as always-false by definition.
- Compare ids/keys or use a deep-equality utility.
- Keep oxlint's correctness category on to catch this at author time.
When it happens
Trigger: BinaryExpression with Equality/Inequality where `is_always_new(left) && is_always_new(right)` — two object/array/function/class/regex literals or builtin-global `new` expressions compared with `==`/`!=`, e.g. `JSON.parse(s) == JSON.parse(s)` style copies compared after literal construction like `[a] == [a]`.
Common situations: Array-of-values comparison written as `[x] == [x]`; comparing two configuration object literals for overlap; refactored `deepEqual` sketches that regressed to `==`.
Related errors
- Unexpected comparison to newly constructed object
- Unexpected constant {lhs_name} on the left-hand side of a {e
- Unexpected constant binary expression
- Unexpected constant relational comparison
- Unexpected constant condition
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/a52162992a701af0.
Report an issue: GitHub.