pve-eslint/eslint/docs/rules/no-unsafe-optional-chaining.md
Thomas Lamprecht 456be15ea9 import eslint 7.18.0
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2021-01-19 16:04:55 +01:00

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;
}
```