Reputation: 321
We've deployed bugs in our node app b/c we forgot to prefix async function calls with "await".
Example:
const getUsers = async () => db.query('SELECT * from Users');
const testMissingAwait = async () => {
const users = getUsers(); // <<< missing await
console.log(users.length);
};
testMissingAwait();
Is there an easy way to find async function calls missing the await keyword?
Failing that, how much effort would it be to write a Visual Studio Code extension that flags these automatically? (I'm up for tackling if anyone can point me in the right direction).
Upvotes: 22
Views: 9428
Reputation: 15995
tslint is deprecated but typescript-eslint has a rule for this: no-floating-promises
This rule forbids usage of Promise-like values in statements without handling their errors appropriately ... Valid ways of handling a Promise-valued statement include
await
ing, returning, and either calling.then()
with two arguments or.catch()
with one argument.
To use it, you'll need to set up typescript-eslint:
Install dependencies
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
Modify your .eslintrc
file
These are the minimum required settings; see the documentation for more options (https://typescript-eslint.io/docs/linting/linting):
{
"parser": "@typescript-eslint/parser",
"parserOptions": { "project": "./tsconfig.json" },
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-floating-promises": ["error"]
}
}
If there are places where you want to call an async function without using await
, you can either:
Use the void
operator as mentioned in the documentation for the rule, e.g.
void someAsyncFunction();
Or just change error
to warn
in the .eslintrc
configuration above
Next time you run eslint you should see the rule applied:
$ npm run lint
...
./src/database/database.ts
219:7 warning Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises
Since you mentioned VS Code specifically, this also integrates great with the ESLint plugin:
Upvotes: 4
Reputation: 21337
TypeScript compiler doesn't provide a compiler option for that. However, TSLint 4.4 provides an option to detect floating promises. You can read this blog post for more detailed answer: Detect missing await in typescript
Download TSLint:
npm install -g tslint typescript
Configure TSLint:
{
"extends": "tslint:recommended",
"rules": {
"no-floating-promises": true
}
}
Run TSLint:
tslint --project tsconfig.json
If there are floating promises in your code, you should see the following error:
ERROR: F:/Samples/index.ts[12, 5]: Promises must be handled appropriately
Upvotes: 6
Reputation: 250942
TypeScript already does this
// users is a Promise<T>
const users = getUsers(); // <<< missing await
// users.length is not a property of users... then and catch are
console.log(users.length);
You can find situations where you won't be told about your mistake - where the types are compatible, for example I missed an await here:
function delay(ms: number) {
return new Promise<number>(function(resolve) {
setTimeout(() => {
resolve(5);
}, ms);
});
}
async function asyncAwait() {
let x = await delay(1000);
console.log(x);
let y = delay(1000);
console.log(y);
return 'Done';
}
asyncAwait().then((result) => console.log(result));
Because console.log
doesn't cause any type incompatibility between my numbers and my promises, the compiler can't tell I have made a mistake.
The only solution here would be a type annotation... but if you're gonna forget an await, you're just as likely to forget a type annotation.
let y: number = delay(1000);
Upvotes: 3