Linter · Rules
no-unsafe-optional-chaining
Disallow optional chaining where undefined throws an error
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
Reported:
const { name } = user?.profile;
for (const item of order?.items) {
ship(item);
}
const all = [...order?.items];
const data = (await response?.json()).data;
Not reported:
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:
const city = (user?.address).city;
const city = user?.address.city;
Options
| Option | Default | What it does |
|---|---|---|
disallowArithmeticOperators | false | Also report an optional chain in arithmetic, such as a?.b + 1, -a?.b, or x += a?.b, where undefined gives NaN. |
const total = cart?.subtotal + shipping;
const total = (cart?.subtotal ?? 0) + shipping;