no-misused-promises
Disallow Promises in places not designed to handle them.
Extending "plugin:@typescript-eslint/recommended-type-checked"
in an ESLint configuration enables this rule.
This rule requires type information to run.
This rule forbids providing Promises to logical locations such as if statements in places where the TypeScript compiler allows them but they are not handled properly.
These situations can often arise due to a missing await
keyword or just a misunderstanding of the way async
functions are handled/awaited.
no-misused-promises
only detects code that provides Promises to incorrect logical locations.
See no-floating-promises
for detecting unhandled Promise statements.
module.exports = {
"rules": {
"@typescript-eslint/no-misused-promises": "error"
}
};
Try this rule in the playground ↗
Options
This rule accepts the following options:
type Options = [
{
checksConditionals?: boolean;
checksSpreads?: boolean;
checksVoidReturn?:
| {
arguments?: boolean;
attributes?: boolean;
properties?: boolean;
returns?: boolean;
variables?: boolean;
}
| boolean;
},
];
const defaultOptions: Options = [
{ checksConditionals: true, checksVoidReturn: true, checksSpreads: true },
];
checksConditionals
If you don't want to check conditionals, you can configure the rule with "checksConditionals": false
:
{
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksConditionals": false
}
]
}
Doing so prevents the rule from looking at code like if (somePromise)
.
Examples of code for this rule with checksConditionals: true
:
Examples
- ❌ Incorrect
- ✅ Correct
const promise = Promise.resolve('value');
if (promise) {
// Do something
}
const val = promise ? 123 : 456;
while (promise) {
// Do something
}
Open in Playgroundconst promise = Promise.resolve('value');
// Always `await` the Promise in a conditional
if (await promise) {
// Do something
}
const val = (await promise) ? 123 : 456;
while (await promise) {
// Do something
}
Open in PlaygroundchecksVoidReturn
Likewise, if you don't want to check functions that return promises where a void return is expected, your configuration will look like this:
{
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": false
}
]
}
You can disable selective parts of the checksVoidReturn
option by providing an object that disables specific checks.
The following options are supported:
arguments
: Disables checking an asynchronous function passed as argument where the parameter type expects a function that returnsvoid
attributes
: Disables checking an asynchronous function passed as a JSX attribute expected to be a function that returnsvoid
properties
: Disables checking an asynchronous function passed as an object property expected to be a function that returnsvoid
returns
: Disables checking an asynchronous function returned in a function whose return type is a function that returnsvoid
variables
: Disables checking an asynchronous function used as a variable whose return type is a function that returnsvoid
For example, if you don't mind that passing a () => Promise<void>
to a () => void
parameter or JSX attribute can lead to a floating unhandled Promise:
{
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": {
"arguments": false,
"attributes": false
}
}
]
}
Examples of code for this rule with checksVoidReturn: true
:
- ❌ Incorrect
- ✅ Correct
[1, 2, 3].forEach(async value => {
await fetch(`/${value}`);
});
new Promise<void>(async (resolve, reject) => {
await fetch('/');
resolve();
});
document.addEventListener('click', async () => {
console.log('synchronous call');
await fetch('/');
console.log('synchronous call');
});
Open in Playground// for-of puts `await` in outer context
for (const value of [1, 2, 3]) {
await doSomething(value);
}
// If outer context is not `async`, handle error explicitly
Promise.all(
[1, 2, 3].map(async value => {
await doSomething(value);
}),
).catch(handleError);
// Use an async IIFE wrapper
new Promise((resolve, reject) => {
// combine with `void` keyword to tell `no-floating-promises` rule to ignore unhandled rejection
void (async () => {
await doSomething();
resolve();
})();
});
// Name the async wrapper to call it later
document.addEventListener('click', () => {
const handler = async () => {
await doSomething();
otherSynchronousCall();
};
try {
synchronousCall();
} catch (err) {
handleSpecificError(err);
}
handler().catch(handleError);
});
Open in PlaygroundchecksSpreads
If you don't want to check object spreads, you can add this configuration:
{
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksSpreads": false
}
]
}
Examples of code for this rule with checksSpreads: true
:
- ❌ Incorrect
- ✅ Correct
const getData = () => fetch('/');
console.log({ foo: 42, ...getData() });
const awaitData = async () => {
await fetch('/');
};
console.log({ foo: 42, ...awaitData() });
Open in Playgroundconst getData = () => fetch('/');
console.log({ foo: 42, ...(await getData()) });
const awaitData = async () => {
await fetch('/');
};
console.log({ foo: 42, ...(await awaitData()) });
Open in PlaygroundWhen Not To Use It
This rule can be difficult to enable on large existing projects that set up many misused Promises. Alternately, if you're not worried about crashes from floating or misused Promises -such as if you have global unhandled Promise handlers registered- then in some cases it may be safe to not use this rule. You might consider using ESLint disable comments for those specific situations instead of completely disabling this rule.
Further Reading
Related To
Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting. See Performance Troubleshooting if you experience performance degredations after enabling type checked rules.