oxc-project/oxc · warning · OxcDiagnostic

Confusing combinations of non-null assertion and assignment

Error message

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

What it means

Assignment variant of typescript/no-confusing-non-null-assertion: the target of a plain `=` assignment is a TSNonNullExpression, as in `a! = b`. The text closely resembles `a != b`, and the assertion on an assignment target is confusing because assignment targets are not type positions where `!` normally asserts. The rule matches AssignmentExpression with operator Assign whose left is a non-null-asserted simple target.

Source

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

    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!(
        r"Confusing combinations of non-null assertion and assignment like `a! {op_str} b`, which looks very similar to not equal `a !{op_str} b`."
    ))
    .with_help(r"Remove the `!`, or wrap the left-hand side in parentheses.")
    .with_label(span)
}

fn confusing_non_null_operator_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        "Confusing combination of non-null assertion and `{op_str}` operator like `a! {op_str} b`, which might be misinterpreted as `!(a {op_str} b)`."
    ))
    .with_help("Remove the `!`, or wrap the left-hand side in parentheses.")
    .with_label(span)
}

fn get_depth_ends_in_bang(expr: &Expression<'_>) -> Option<u32> {
    match expr {
        Expression::TSNonNullExpression(_) => Some(0),
        Expression::ChainExpression(chain_expr) => {

View on GitHub (pinned to 36ec0ef2ba)

Solutions

  1. Remove the `!` from the assignment target: `foo.bar = value;`
  2. If the target may be nullish, assign through a checked reference: `const slot = foo.bar; if (slot) slot.value = v;`
  3. Wrap the LHS in parentheses if the assertion must stay: `(foo.bar!) = value;`

Example fix

// before
foo.bar! = computeValue();

// after
foo.bar = computeValue();
Defensive patterns

Strategy: type-guard

Validate before calling

// .oxlintrc.json
{
  "rules": { "typescript/no-confusing-non-null-assertion": "warn" }
}

Type guard

function withDefined<T, R>(
  v: T | null | undefined,
  fn: (value: T) => R,
): R | undefined {
  return v === null || v === undefined ? undefined : fn(v);
}

// instead of `foo.bar! = value;` — assignment targets never need `!`
foo.bar = value;
// for maybe-nullish containers, narrow first:
withDefined(container.slot, (slot) => { slot.value = v; });

Prevention

When it happens

Trigger: `foo.bar! = value;`, `map.get(k)! = v;` (any `expr! = value`). Note `a !== b` comparisons never hit this branch; only real assignments with `=` do.

Common situations: Attempting to assert the type of a slot being written to (a misunderstanding of `!`, which only applies to reads); typos where the developer meant `!=`; copy-paste from comparison code into assignment code.

Related errors


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