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
- Remove the `!` from the assignment target: `foo.bar = value;`
- If the target may be nullish, assign through a checked reference: `const slot = foo.bar; if (slot) slot.value = v;`
- 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
- Remember `!` only applies to value reads, never to assignment targets — delete it on the left of `=`
- Watch for the a! = b vs a != b mixup in reviews of assertion-heavy code
- Let the TS compiler surface the real error: removing `!` from a target is always safe syntactically
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
- Confusing combinations of non-null assertion and equal test
- Confusing combination of non-null assertion and `{op_str}` o
- encountered allocation error
- Do not use @ts-{ts_comment_name} because it alters compilati
- Use "@ts-expect-error" instead of @ts-ignore, as "@ts-ignore
AI-assisted analysis of oxc-project/oxc@36ec0ef2ba (2026-08-20).
Data as JSON: /api/errors/b833a1911dbae7d0.
Report an issue: GitHub.