no-unsafe-optional-chaining

Disallow optional chaining where undefined throws an error

error by default

user?.profile is undefined when user is missing. If you then destructure that result, spread it into an array or a call, loop over it, call it, or read a property of it, you get the TypeError that ?. was there to prevent.

The same goes for the right side of in and instanceof, and for extends. The rule also finds a chain behind await, &&, or ? :, and on the right of || or ??.

This rule is on by default.

Configure#

On by default as an error. To turn it off:

bunfig.toml
[lint.rules]
"no-unsafe-optional-chaining" = "off" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"no-unsafe-optional-chaining" = ["error", {
  disallowArithmeticOperators = false,
}]

Examples#

example.js4 problems
const { name } = user?.profile;

for (const item of order?.items) {
  ship(item);
}

const all = [...order?.items];

const data = (await response?.json()).data;
example.jsNo problems
const { name } = user?.profile ?? {};

for (const item of order?.items ?? []) {
  ship(item);
}

const all = [...(order?.items ?? [])];

const data = (await response?.json())?.data;

Parentheses end the chain. Without them, everything after ?. is skipped when user is missing:

example.js1 problem
const city = (user?.address).city;
example.jsNo problems
const city = user?.address.city;

Options#

OptionDefaultWhat it does
disallowArithmeticOperatorsfalseAlso report an optional chain in arithmetic, such as a?.b + 1, -a?.b, or x += a?.b, where undefined gives NaN.
example.jswith { "disallowArithmeticOperators": true }1 problem
const total = cart?.subtotal + shipping;
example.jswith { "disallowArithmeticOperators": true }No problems
const total = (cart?.subtotal ?? 0) + shipping;