oxc-project/oxc · warning · OxcDiagnostic

Confusing combinations of non-null assertion and equal test

Error message

Confusing combinations of non-null assertion and equal test like `a! {op_str} b`, which looks very similar to not equal `a !{op_str} b`.

What it means

typescript/no-confusing-non-null-assertion flags binary expressions with ==, ===, !=, !== whose left side ends in a non-null assertion `!`. When the expression ends directly in `!` at depth 0 (e.g. `a! === b`), this variant is emitted because the text looks like the negated comparison `a !== b` / `a != b` with one stray space.

Source

Thrown at crates/oxc_linter/src/rules/typescript/no_confusing_non_null_assertion.rs:58

    ///    a! instanceof b;
    /// ```
    ///
    /// Examples of **correct** code for this rule:
    /// ```ts
    /// a == b;
    /// a !== b;
    /// a === b;
    /// ```
    NoConfusingNonNullAssertion,
    typescript,
    suspicious,
    suggestion,
    version = "0.6.1",
    short_description = "Disallow non-null assertion in locations that may be confusing.",
);

fn not_need_no_confusing_non_null_assertion_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        r"Confusing combinations of non-null assertion and equal test like `a! {op_str} b`, which looks very similar to not equal `a !{op_str} b`."
    ))
    .with_help(r"Remove the `!`, or prefix the `=` with it.")
    .with_label(span)
}

fn wrap_up_no_confusing_non_null_assertion_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        r"Confusing combinations of non-null assertion and equal test like `a! {op_str} b`, which looks very similar to not equal `a !{op_str} b`."
    ))
    .with_help(
        r"Wrap left-hand side in parentheses to avoid putting non-null assertion `!` and `=` together.",
    )
    .with_label(span)
}

fn confusing_non_null_assignment_assertion_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(

View on GitHub (pinned to 36ec0ef2ba)

Solutions

  1. If you meant the comparison, remove the `!`: `a === b`
  2. If you meant negation, prefix the `=` with the `!`: write `a !== b` instead of `a! == b`
  3. If the assertion is intentional, disambiguate by wrapping: `(a!) === b`

Example fix

// before (assertion intended)
if (a! == b) {}

// after
if (a === b) {} // no assertion needed
// or, if the assertion is intentional:
if ((a!) === b) {}
Defensive patterns

Strategy: type-guard

Validate before calling

// Keep the rule on in CI so visual-confusion comparisons never land:
// .oxlintrc.json
{
  "rules": { "typescript/no-confusing-non-null-assertion": "warn" }
}

Type guard

function isDefined<T>(v: T | null | undefined): v is T {
  return v !== null && v !== undefined;
}

// instead of `a! === b`, narrow first
if (isDefined(a)) {
  if (a === b) { /* ... */ }
}

Prevention

When it happens

Trigger: `a! == b`, `a! === b`, `a! != b`, `a! !== b` where the LHS is a plain TSNonNullExpression (bang_depth == 0 in get_depth_ends_in_bang); also `a!.b! === c` style chains ending in `!`.

Common situations: Developers intending `a !== b` but typing `a! == b` or vice versa; optional-heavy code where `!` assertions are habitual; typos that are syntactically valid and silently change meaning.

Related errors


AI-assisted analysis of oxc-project/oxc@36ec0ef2ba (2026-08-20). Data as JSON: /api/errors/f52af5a1ef54aa30. Report an issue: GitHub.