{"record":{"id":"b833a1911dbae7d0","repo":"oxc-project/oxc","slug":"confusing-combinations-of-non-null-assertion-and-a","errorCode":null,"errorMessage":"Confusing combinations of non-null assertion and assignment like `a! {op_str} b`, which looks very similar to not equal `a !{op_str} b`.","messagePattern":"Confusing combinations of non-null assertion and assignment like `a! (.+?) b`, which looks very similar to not equal `a !(.+?) b`\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/typescript/no_confusing_non_null_assertion.rs","lineNumber":76,"sourceCode":"    OxcDiagnostic::warn(format!(\n        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`.\"\n    ))\n    .with_help(r\"Remove the `!`, or prefix the `=` with it.\")\n    .with_label(span)\n}\n\nfn wrap_up_no_confusing_non_null_assertion_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\n        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`.\"\n    ))\n    .with_help(\n        r\"Wrap left-hand side in parentheses to avoid putting non-null assertion `!` and `=` together.\",\n    )\n    .with_label(span)\n}\n\nfn confusing_non_null_assignment_assertion_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\n        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`.\"\n    ))\n    .with_help(r\"Remove the `!`, or wrap the left-hand side in parentheses.\")\n    .with_label(span)\n}\n\nfn confusing_non_null_operator_diagnostic(op_str: &str, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\n        \"Confusing combination of non-null assertion and `{op_str}` operator like `a! {op_str} b`, which might be misinterpreted as `!(a {op_str} b)`.\"\n    ))\n    .with_help(\"Remove the `!`, or wrap the left-hand side in parentheses.\")\n    .with_label(span)\n}\n\nfn get_depth_ends_in_bang(expr: &Expression<'_>) -> Option<u32> {\n    match expr {\n        Expression::TSNonNullExpression(_) => Some(0),\n        Expression::ChainExpression(chain_expr) => {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/oxc-project/oxc/blob/36ec0ef2bae567d1a8413ada2fe795f1af1f2785/crates/oxc_linter/src/rules/typescript/no_confusing_non_null_assertion.rs#L58-L94","documentation":"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.","triggerScenarios":"`foo.bar! = value;`, `map.get(k)! = v;` (any `expr! = value`). Note `a !== b` comparisons never hit this branch; only real assignments with `=` do.","commonSituations":"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.","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;`"],"exampleFix":"// before\nfoo.bar! = computeValue();\n\n// after\nfoo.bar = computeValue();","handlingStrategy":"type-guard","validationCode":"// .oxlintrc.json\n{\n  \"rules\": { \"typescript/no-confusing-non-null-assertion\": \"warn\" }\n}","typeGuard":"function withDefined<T, R>(\n  v: T | null | undefined,\n  fn: (value: T) => R,\n): R | undefined {\n  return v === null || v === undefined ? undefined : fn(v);\n}\n\n// instead of `foo.bar! = value;` — assignment targets never need `!`\nfoo.bar = value;\n// for maybe-nullish containers, narrow first:\nwithDefined(container.slot, (slot) => { slot.value = v; });","tryCatchPattern":null,"preventionTips":["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"],"tags":["typescript","lint","non-null-assertion","assignment","oxlint"],"backgroundTag":"non-null-assertion-assignment","analyzedSha":"36ec0ef2bae567d1a8413ada2fe795f1af1f2785","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}