Skip to content

Commit 28a131d

Browse files
princjefbradzacher
authored andcommitted
feat(eslint-plugin): add new rule no-misused-promises (#612)
* feat(eslint-plugin): add new rule no-misused-promises * chore: review feedback * chore: regenerate plugin configs
1 parent ceb2d32 commit 28a131d

File tree

9 files changed

+662
-3
lines changed

9 files changed

+662
-3
lines changed

packages/eslint-plugin/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
152152
| [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean | :heavy_check_mark: | :wrench: | |
153153
| [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallows magic numbers | | | |
154154
| [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor` | :heavy_check_mark: | | |
155+
| [`@typescript-eslint/no-misused-promises`](./docs/rules/no-misused-promises.md) | Avoid using promises in places not designed to handle them | | | :thought_balloon: |
155156
| [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces | :heavy_check_mark: | | |
156157
| [`@typescript-eslint/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator | :heavy_check_mark: | | |
157158
| [`@typescript-eslint/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) | Forbids an object literal to appear in a type assertion expression | :heavy_check_mark: | | |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Avoid using promises in places not designed to handle them (no-misused-promises)
2+
3+
This rule forbids using promises in places where the Typescript compiler
4+
allows them but they are not handled properly. These situations can often arise
5+
due to a missing `await` keyword or just a misunderstanding of the way async
6+
functions are handled/awaited.
7+
8+
## Rule Details
9+
10+
Examples of **incorrect** code for this rule with `checksConditionals: true`:
11+
12+
```ts
13+
const promise = Promise.resolve('value');
14+
15+
if (promise) {
16+
// Do something
17+
}
18+
19+
const val = promise ? 123 : 456;
20+
21+
while (promise) {
22+
// Do something
23+
}
24+
```
25+
26+
Examples of **incorrect** code for this rule with `checksVoidReturn: true`:
27+
28+
```ts
29+
[1, 2, 3].forEach(async value => {
30+
await doSomething(value);
31+
});
32+
33+
new Promise(async (resolve, reject) => {
34+
await doSomething();
35+
resolve();
36+
});
37+
38+
const eventEmitter = new EventEmitter();
39+
eventEmitter.on('some-event', async () => {
40+
await doSomething();
41+
});
42+
```
43+
44+
Examples of **correct** code for this rule:
45+
46+
```ts
47+
const promise = Promise.resolve('value');
48+
49+
if (await promise) {
50+
// Do something
51+
}
52+
53+
const val = (await promise) ? 123 : 456;
54+
55+
while (await promise) {
56+
// Do something
57+
}
58+
59+
for (const value of [1, 2, 3]) {
60+
await doSomething(value);
61+
}
62+
63+
new Promise((resolve, reject) => {
64+
// Do something
65+
resolve();
66+
});
67+
68+
const eventEmitter = new EventEmitter();
69+
eventEmitter.on('some-event', () => {
70+
doSomething();
71+
});
72+
```
73+
74+
## Options
75+
76+
This rule accepts a single option which is an object with `checksConditionals`
77+
and `checksVoidReturn` properties indicating which types of misuse to flag.
78+
Both are enabled by default
79+
80+
If you don't want functions that return promises where a void return is
81+
expected to be checked, your configuration will look like this:
82+
83+
```json
84+
{
85+
"@typescript-eslint/no-misused-promises": [
86+
"error",
87+
{
88+
"checksVoidReturn": false
89+
}
90+
]
91+
}
92+
```
93+
94+
Likewise, if you don't want to check conditionals, you can configure the rule
95+
like this:
96+
97+
```json
98+
{
99+
"@typescript-eslint/no-misused-promises": [
100+
"error",
101+
{
102+
"checksConditionals": false
103+
}
104+
]
105+
}
106+
```
107+
108+
## When Not To Use It
109+
110+
If you do not use Promises in your codebase or are not concerned with possible
111+
misuses of them outside of what the Typescript compiler will check.
112+
113+
## Related to
114+
115+
- [`no-floating-promises`]('./no-floating-promises.md')
116+
117+
## Further Reading
118+
119+
- [Typescript void function assignability](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-returning-non-void-assignable-to-function-returning-void)

packages/eslint-plugin/src/configs/all.json

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"no-magic-numbers": "off",
3737
"@typescript-eslint/no-magic-numbers": "error",
3838
"@typescript-eslint/no-misused-new": "error",
39+
"@typescript-eslint/no-misused-promises": "error",
3940
"@typescript-eslint/no-namespace": "error",
4041
"@typescript-eslint/no-non-null-assertion": "error",
4142
"@typescript-eslint/no-object-literal-type-assertion": "error",

packages/eslint-plugin/src/configs/base.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
"parserOptions": {
44
"sourceType": "module"
55
},
6-
"plugins": ["@typescript-eslint"]
6+
"plugins": [
7+
"@typescript-eslint"
8+
]
79
}

packages/eslint-plugin/src/configs/recommended.json

-2
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@
2424
"@typescript-eslint/no-non-null-assertion": "error",
2525
"@typescript-eslint/no-object-literal-type-assertion": "error",
2626
"@typescript-eslint/no-parameter-properties": "error",
27-
"@typescript-eslint/no-triple-slash-reference": "error",
2827
"no-unused-vars": "off",
2928
"@typescript-eslint/no-unused-vars": "warn",
3029
"no-use-before-define": "off",
3130
"@typescript-eslint/no-use-before-define": "error",
3231
"@typescript-eslint/no-var-requires": "error",
33-
"@typescript-eslint/prefer-interface": "error",
3432
"@typescript-eslint/prefer-namespace-keyword": "error",
3533
"@typescript-eslint/type-annotation-spacing": "error"
3634
}

packages/eslint-plugin/src/rules/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import noForInArray from './no-for-in-array';
2727
import noInferrableTypes from './no-inferrable-types';
2828
import noMagicNumbers from './no-magic-numbers';
2929
import noMisusedNew from './no-misused-new';
30+
import noMisusedPromises from './no-misused-promises';
3031
import noNamespace from './no-namespace';
3132
import noNonNullAssertion from './no-non-null-assertion';
3233
import noObjectLiteralTypeAssertion from './no-object-literal-type-assertion';
@@ -89,6 +90,7 @@ export default {
8990
'no-inferrable-types': noInferrableTypes,
9091
'no-magic-numbers': noMagicNumbers,
9192
'no-misused-new': noMisusedNew,
93+
'no-misused-promises': noMisusedPromises,
9294
'no-namespace': noNamespace,
9395
'no-non-null-assertion': noNonNullAssertion,
9496
'no-object-literal-type-assertion': noObjectLiteralTypeAssertion,

0 commit comments

Comments
 (0)