no-floating-promises
Require Promise-like statements to be handled appropriately.
Extending "plugin:@typescript-eslint/recommended-type-checked"
in an ESLint configuration enables this rule.
Some problems reported by this rule are manually fixable by editor suggestions.
This rule requires type information to run.
A "floating" Promise is one that is created without any code set up to handle any errors it might throw. Floating Promises can cause several issues, such as improperly sequenced operations, ignored Promise rejections, and more.
This rule reports when a Promise is created and not properly handled. Valid ways of handling a Promise-valued statement include:
await
ing itreturn
ing itvoid
ing it- Calling its
.then()
with two arguments - Calling its
.catch()
with one argument
This rule also reports when an Array containing Promises is created and not properly handled. The main way to resolve this is by using one of the Promise concurrency methods to create a single Promise, then handling that according to the procedure above. These methods include:
Promise.all()
Promise.allSettled()
Promise.any()
Promise.race()
no-floating-promises
only detects unhandled Promise statements.
See no-misused-promises
for detecting code that provides Promises to logical locations such as if statements.
module.exports = {
"rules": {
"@typescript-eslint/no-floating-promises": "error"
}
};
Try this rule in the playground ↗
Examples
- ❌ Incorrect
- ✅ Correct
const promise = new Promise((resolve, reject) => resolve('value'));
promise;
async function returnsPromise() {
return 'value';
}
returnsPromise().then(() => {});
Promise.reject('value').catch();
Promise.reject('value').finally();
[1, 2, 3].map(async x => x + 1);
Open in Playgroundconst promise = new Promise((resolve, reject) => resolve('value'));
await promise;
async function returnsPromise() {
return 'value';
}
void returnsPromise();
returnsPromise().then(
() => {},
() => {},
);
Promise.reject('value').catch(() => {});
await Promise.reject('value').finally(() => {});
await Promise.all([1, 2, 3].map(async x => x + 1));
Open in PlaygroundOptions
This rule accepts the following options:
type Options = [
{
allowForKnownSafeCalls?: (
| {
from: 'file';
name: [string, ...string[]] | string;
path?: string;
}
| {
from: 'lib';
name: [string, ...string[]] | string;
}
| {
from: 'package';
name: [string, ...string[]] | string;
package: string;
}
| string
)[];
allowForKnownSafePromises?: (
| {
from: 'file';
name: [string, ...string[]] | string;
path?: string;
}
| {
from: 'lib';
name: [string, ...string[]] | string;
}
| {
from: 'package';
name: [string, ...string[]] | string;
package: string;
}
| string
)[];
/** Whether to check all "Thenable"s, not just the built-in Promise type. */
checkThenables?: boolean;
/** Whether to ignore async IIFEs (Immediately Invoked Function Expressions). */
ignoreIIFE?: boolean;
/** Whether to ignore `void` expressions. */
ignoreVoid?: boolean;
},
];
const defaultOptions: Options = [
{
allowForKnownSafeCalls: [],
allowForKnownSafePromises: [],
checkThenables: false,
ignoreIIFE: false,
ignoreVoid: true,
},
];
checkThenables
A "Thenable" value is an object which has a then
method, such as a Promise
.
Other Thenables include TypeScript's built-in PromiseLike
interface and any custom object that happens to have a .then()
.
The checkThenables
option triggers no-floating-promises
to also consider all values that satisfy the Thenable shape (a .then()
method that takes two callback parameters), not just Promises.
This can be useful if your code works with older Promise
polyfills instead of the native Promise
class.
- ❌ Incorrect
- ✅ Correct
declare function createPromiseLike(): PromiseLike<string>;
createPromiseLike();
interface MyThenable {
then(onFulfilled: () => void, onRejected: () => void): MyThenable;
}
declare function createMyThenable(): MyThenable;
createMyThenable();
Open in Playgrounddeclare function createPromiseLike(): PromiseLike<string>;
await createPromiseLike();
interface MyThenable {
then(onFulfilled: () => void, onRejected: () => void): MyThenable;
}
declare function createMyThenable(): MyThenable;
await createMyThenable();
Open in PlaygroundignoreVoid
This option, which is true
by default, allows you to stop the rule reporting promises consumed with void operator.
This can be a good way to explicitly mark a promise as intentionally not awaited.
Examples of correct code for this rule with { ignoreVoid: true }
:
async function returnsPromise() {
return 'value';
}
void returnsPromise();
void Promise.reject('value');
Open in PlaygroundWith this option set to true
, and if you are using no-void
, you should turn on the allowAsStatement
option.
ignoreIIFE
This allows you to skip checking of async IIFEs (Immediately Invoked Function Expressions).
Examples of correct code for this rule with { ignoreIIFE: true }
:
await (async function () {
await res(1);
})();
(async function () {
await res(1);
})();
Open in PlaygroundallowForKnownSafePromises
This option allows marking specific types as "safe" to be floating. For example, you may need to do this in the case of libraries whose APIs return Promises whose rejections are safely handled by the library.
This option takes an array of type specifiers to consider safe. Each item in the array must have one of the following forms:
- A type defined in a file (
{ from: "file", name: "Foo", path: "src/foo-file.ts" }
withpath
being an optional path relative to the project root directory) - A type from the default library (
{ from: "lib", name: "PromiseLike" }
) - A type from a package (
{ from: "package", name: "Foo", package: "foo-lib" }
, this also works for types defined in a typings package).
Examples of code for this rule with:
{
"allowForKnownSafePromises": [
{ "from": "file", "name": "SafePromise" },
{ "from": "lib", "name": "PromiseLike" },
{ "from": "package", "name": "Bar", "package": "bar-lib" }
]
}
- ❌ Incorrect
- ✅ Correct
let promise: Promise<number> = Promise.resolve(2);
promise;
function returnsPromise(): Promise<number> {
return Promise.resolve(42);
}
returnsPromise();
Open in Playground// promises can be marked as safe by using branded types
type SafePromise = Promise<number> & { __linterBrands?: string };
let promise: SafePromise = Promise.resolve(2);
promise;
function returnsSafePromise(): SafePromise {
return Promise.resolve(42);
}
returnsSafePromise();
Open in PlaygroundallowForKnownSafeCalls
This option allows marking specific functions as "safe" to be called to create floating Promises. For example, you may need to do this in the case of libraries whose APIs may be called without handling the resultant Promises.
This option takes the same array format as allowForKnownSafePromises
.
Examples of code for this rule with:
{
"allowForKnownSafeCalls": [
{ "from": "file", "name": "safe", "path": "input.ts" }
]
}
- ❌ Incorrect
- ✅ Correct
declare function unsafe(...args: unknown[]): Promise<void>;
unsafe('...', () => {});
Open in Playgrounddeclare function safe(...args: unknown[]): Promise<void>;
safe('...', () => {});
Open in PlaygroundWhen Not To Use It
This rule can be difficult to enable on large existing projects that set up many floating 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 void
s and/or ESLint disable comments for those specific situations instead of completely disabling this rule.
Related To
Further Reading
- "Using Promises" MDN documentation. Note especially the sections on Promise rejection events and Composition.
Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting. See Troubleshooting > Linting with Type Information > Performance if you experience performance degredations after enabling type checked rules.