Flow can now detect unused Promises

David Richey
Flow
Published in
2 min readApr 10, 2023

As of v0.201.0, Flow can now lint against unused/floating Promises. Unused promises can be dangerous, because errors are potentially unhandled, and the code may not execute in the intended order. They are usually mistakes that Flow is perfectly positioned to warn you about.

A promise can be “used” by…

  • awaiting it
  • Calling .then with a rejection handler (i.e., with two arguments)
  • Calling .catch
  • Calling .finally
  • Storing it in a variable, passing it to a function, etc.

Some examples:

// The promise returned by foo might fail
function foo(): Promise<string> {
Math.random() > 0.5
? Promise.resolve("example")
: Promise.reject(new Error("error"));
}

async function bar() {
const x = foo(); // ok
await foo(); // ok
foo(); // error: `Promise` in async scope is unused. Did you mean to `await` it?
}

function baz() {
baz(foo()); // ok
foo().catch(e => /*...*/); // ok
foo().then(s => /* ... */); // error: `Promise` in sync scope is unused. Promises must be handled by calling .then with a rejection handler, .catch, or .finally.
foo(); // error
}

Fire-and-forget

If you know it is safe to do so, you can explicitly ignore a promise using JavaScript’s void operator. This has the same effect as suppressing the lint error.

async function baz() {
// I know what I'm doing!
void foo(); // ok
}

Quick fixes

We have added two quick fixes to help fix errors raised by this lint:

  1. “Insert await” will transform foo() to await foo(). This is only suggested when in an async context.
  2. “Insert void” will transform foo() to void foo().

Configuration

The lint can be configured like any other in your project’s .flowconfig:

[lints]
unused-promise=error

See our linting documentation for more information (by the way, a lot of our docs have recently been revamped, check it out!).

Prior art

The rules of this lint are the same as typescript-eslint’s no-floating-promises rule.

--

--