oxc-project/oxc · warning · OxcDiagnostic
Unsafe arithmetic operation on optional chaining
Error message
Unsafe arithmetic operation on optional chaining
What it means
Second diagnostic of no-unsafe-optional-chaining, emitted only when the disallowArithmeticOperators option is enabled. Arithmetic on a possibly-undefined optional chain yields NaN instead of throwing, silently corrupting numeric results (help text: 'This can result in NaN.').
Source
Thrown at crates/oxc_linter/src/rules/eslint/no_unsafe_optional_chaining.rs:26
use oxc_span::Span;
use oxc_syntax::operator::LogicalOperator;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
fn no_unsafe_optional_chaining_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unsafe usage of optional chaining")
.with_help("If this short-circuits with 'undefined' the evaluation will throw TypeError")
.with_label(span)
}
fn no_unsafe_arithmetic_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Unsafe arithmetic operation on optional chaining")
.with_help("This can result in NaN.")
.with_label(span)
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoUnsafeOptionalChaining {
/// Disallow arithmetic operations on optional chaining expressions.
/// If this is true, this rule warns arithmetic operations on optional chaining expressions, which possibly result in NaN.
disallow_arithmetic_operators: bool,
}
declare_oxc_lint!(
/// ### What it does
///
/// Disallow use of optional chaining in contexts where the `undefined` value is not allowed.
///
/// ### Why is this bad?View on GitHub (pinned to e1e7af627c)
Solutions
- Default the chain before arithmetic: (cart?.total ?? 0) + shipping.
- Guard the object first: if (cart) total = cart.total + shipping.
- If NaN propagation is acceptable in your domain, leave "disallowArithmeticOperators": false (default).
Example fix
// before const grandTotal = cart?.total + shipping; // after const grandTotal = (cart?.total ?? 0) + shipping;
Defensive patterns
Strategy: type-guard
Validate before calling
const total = (cart?.total ?? 0) + shipping; // default before arithmetic
Type guard
const isNum = (v: unknown): v is number => typeof v === 'number' && !Number.isNaN(v);
Prevention
- Wrap every optional chain in (chain ?? default) before arithmetic.
- Enable "disallowArithmeticOperators": true when NaN propagation is unacceptable (money, counters, metrics).
- Add Number.isNaN assertions in tests for aggregation code over optional data.
When it happens
Trigger: Set "disallowArithmeticOperators": true on the rule in .oxlintrc.json, then write cart?.total + shipping, count?.valueOf() * 2, or (opts?.retries) - 1 without a default.
Common situations: Teams enabling the stricter option over a codebase already doing arithmetic on optional API data; money/count aggregation over maybe-missing objects.
Related errors
- Unsafe usage of optional chaining
- Checking inequality with NaN will always return true
- Checking equality with NaN will always return false
- Comparison with NaN will always return false
- Checking `switch` discriminant against NaN will never match
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/500dc6ee70057996.
Report an issue: GitHub.