mirror of
https://git.proxmox.com/git/pve-eslint
synced 2025-10-12 00:46:20 +00:00
154 lines
3.1 KiB
Markdown
154 lines
3.1 KiB
Markdown
# disallow use of optional chaining in contexts where the `undefined` value is not allowed (no-unsafe-optional-chaining)
|
|
|
|
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:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
var obj = undefined;
|
|
|
|
(obj?.foo)(); // TypeError
|
|
(obj?.foo).bar; // TypeError
|
|
```
|
|
|
|
## Rule Details
|
|
|
|
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:
|
|
|
|
```js
|
|
/*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:
|
|
|
|
```js
|
|
/*eslint no-unsafe-optional-chaining: "error"*/
|
|
|
|
(obj?.foo)?.();
|
|
|
|
obj?.foo();
|
|
|
|
(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;
|
|
}
|
|
```
|
|
|
|
## Options
|
|
|
|
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`.
|
|
|
|
### disallowArithmeticOperators
|
|
|
|
With this option set to `true` the rule is enforced for:
|
|
|
|
- Unary operators: `-`, `+`
|
|
- Arithmetic operators: `+`, `-`, `/`, `*`, `%`, `**`
|
|
- Assignment operators: `+=`, `-=`, `/=`, `*=`, `%=`, `**=`
|
|
|
|
Examples of additional **incorrect** code for this rule with the `{ "disallowArithmeticOperators": true }` option:
|
|
|
|
```js
|
|
/*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;
|
|
}
|
|
```
|