Disallow use of optional chaining in contexts where the undefined
value is not allowed
The "extends": "eslint:recommended"
property in a configuration file enables this rule
The optional chaining (?.
) expression can short-circuit with a return value of undefined
. Therefore, treating an evaluated optional chaining expression as a function, object, number, etc., can cause TypeError or unexpected results. For example:
var obj = undefined;
1 in obj?.foo; // TypeError
with (obj?.foo); // TypeError
for (bar of obj?.foo); // TypeError
bar instanceof obj?.foo; // TypeError
const { bar } = obj?.foo; // TypeError
Also, parentheses limit the scope of short-circuiting in chains. For example:
var obj = undefined;
(obj?.foo)(); // TypeError
(obj?.foo).bar; // TypeError
This rule aims to detect some cases where the use of optional chaining doesn’t prevent runtime errors. In particular, it flags optional chaining expressions in positions where short-circuiting to undefined
causes throwing a TypeError afterward.
Examples of incorrect code for this rule:
/*eslint no-unsafe-optional-chaining: "error"*/
(obj?.foo)();
(obj?.foo).bar;
(foo?.()).bar;
(foo?.()).bar();
(obj?.foo ?? obj?.bar)();
(foo || obj?.foo)();
(obj?.foo && foo)();
(foo ? obj?.foo : bar)();
(foo, obj?.bar).baz;
(obj?.foo)`template`;
new (obj?.foo)();
[...obj?.foo];
bar(...obj?.foo);
1 in obj?.foo;
bar instanceof obj?.foo;
for (bar of obj?.foo);
const { bar } = obj?.foo;
[{ bar } = obj?.foo] = [];
with (obj?.foo);
class A extends obj?.foo {}
var a = class A extends obj?.foo {};
async function foo () {
const { bar } = await obj?.foo;
(await obj?.foo)();
(await obj?.foo).bar;
}
Examples of correct code for this rule:
/*eslint no-unsafe-optional-chaining: "error"*/
(obj?.foo)?.();
obj?.foo();
(obj?.foo ?? bar)();
obj?.foo.bar;
obj.foo?.bar;
foo?.()?.bar;
(obj?.foo ?? bar)`template`;
new (obj?.foo ?? bar)();
var baz = {...obj?.foo};
const { bar } = obj?.foo || baz;
async function foo () {
const { bar } = await obj?.foo || baz;
(await obj?.foo)?.();
(await obj?.foo)?.bar;
}
This rule has an object option:
disallowArithmeticOperators
: Disallow arithmetic operations on optional chaining expressions (Default false
). If this is true
, this rule warns arithmetic operations on optional chaining expressions, which possibly result in NaN
.With this option set to true
the rule is enforced for:
-
, +
+
, -
, /
, *
, %
, **
+=
, -=
, /=
, *=
, %=
, **=
Examples of additional incorrect code for this rule with the { "disallowArithmeticOperators": true }
option:
/*eslint no-unsafe-optional-chaining: ["error", { "disallowArithmeticOperators": true }]*/
+obj?.foo;
-obj?.foo;
obj?.foo + bar;
obj?.foo - bar;
obj?.foo / bar;
obj?.foo * bar;
obj?.foo % bar;
obj?.foo ** bar;
baz += obj?.foo;
baz -= obj?.foo;
baz /= obj?.foo;
baz *= obj?.foo;
baz %= obj?.foo;
baz **= obj?.foo;
async function foo () {
+await obj?.foo;
await obj?.foo + bar;
baz += await obj?.foo;
}
This rule was introduced in ESLint v7.15.0.
© OpenJS Foundation and other contributors
Licensed under the MIT License.
https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining