{"record":{"id":"f615ecfa4ccdda92","repo":"oxc-project/oxc","slug":"optional-chain-expressions-can-return-undefined-by","errorCode":null,"errorMessage":"Optional chain expressions can return undefined by design: using a non-null assertion is unsafe and wrong.","messagePattern":"Optional chain expressions can return undefined by design: using a non-null assertion is unsafe and wrong\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/typescript/no_non_null_asserted_optional_chain.rs","lineNumber":19,"sourceCode":"use oxc_ast::{\n    AstKind,\n    ast::{ChainElement, Expression, match_member_expression},\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::{GetSpan, Span};\n\nuse crate::{\n    AstNode,\n    context::{ContextHost, LintContext},\n    rule::Rule,\n};\n\nfn no_non_null_asserted_optional_chain_diagnostic(\n    chain_span: Span,\n    assertion_span: Span,\n) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"Optional chain expressions can return undefined by design: using a non-null assertion is unsafe and wrong.\")\n        .with_help(\"Remove the non-null assertion.\")\n        .with_label(assertion_span.primary_label(\"non-null assertion made after optional chain\"))\n        .and_label(chain_span.label(\"optional chain used\"))\n}\n\n#[derive(Debug, Default, Clone)]\npub struct NoNonNullAssertedOptionalChain;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Disallow non-null assertions after an optional chain expression.\n    ///\n    /// ### Why is this bad?\n    ///\n    /// By design, optional chain expressions (`?.`) provide `undefined` as the expression's value, if the object being\n    /// accessed is `null` or `undefined`, instead of throwing an error. Using a non-null assertion (`!`) to assert the\n    /// result of an optional chain expression is contradictory and likely wrong, as it indicates the code is both expecting","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/typescript/no_non_null_asserted_optional_chain.rs#L1-L37","documentation":"Oxlint's no-non-null-asserted-optional-chain: `foo?.bar!` asserts non-null on the result of a chain that by design yields `undefined` when a link is missing. The warn text at no_non_null_asserted_optional_chain.rs:23 calls this unsafe and wrong, and the diagnostic carries two labels: the assertion as primary and the chain as secondary (the two spans in the function signature at lines 14-17).","triggerScenarios":"`foo?.bar!`, `foo?.()!.toString()`, `map.get(k)?.value!` - a postfix `!` applied to the result of an optional chain expression.","commonSituations":"Developers forcing away 'possibly undefined' compiler errors, then hitting runtime crashes exactly when the chain short-circuits; migration code where nullability was poorly understood.","solutions":["Remove the `!` and let the chain propagate undefined (`foo?.bar?.city`)","Provide a fallback with `??`","Add an explicit early return or throw when the value is undefined","Restructure so the optional link is not needed"],"exampleFix":"// before\nconst city = user?.address!.city;\n\n// after\nconst city = user?.address?.city;","handlingStrategy":"validation","validationCode":"npx oxlint --deny-warnings .","typeGuard":"function isDefined<T>(value: T | null | undefined): value is T {\n  return value !== null && value !== undefined;\n}\n\n// usage instead of `user?.address!.city`\nconst address = user?.address;\nif (!isDefined(address)) return;\ndoWork(address.city);","tryCatchPattern":null,"preventionTips":["Never postfix `!` on anything containing `?.`; treat it as a bug pattern","Handle the undefined case with `??` or an early return","Enable strictNullChecks so the short-circuit case is visible in the type"],"tags":["typescript","lint","optional-chaining","non-null-assertion","null-safety"],"backgroundTag":"non-null-asserted-optional-chain","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}