Detect missing await in TypeScript

Using promises in JavaScript/TypeScript is very common. More and more APIs use them, including the ones provided by the browser such as fetch or Service worker registration. Using the async/await syntax, promises are very convenient to use.

function delay(ms: number) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function simulateLongComputation() {
    await delay(100);
    return 42;
}

However, it's also very easy to forget awaiting a promise, mainly if you are refactoring your code. Even when you don't await a promise, the ts file is perfectly valid, so the TypeScript compiler can compile without error. But the code does not behave as expected. This pattern is called fire and forget because you start a promise but you'll never get the result of the promise (success or failure). This is not ofen what you want.

function checkValueAsync(value: any) {
    return new Promise((resolve, reject) => {
        if (value) {
            resolve();
        } else {
            reject();
        }
    });
}

try {
    checkValueAsync(null); // missing await here
} catch (ex) {
    console.log(ex); // no error, because the promise is not awaited
}

The only information is an error in the console if the promise failed:

Google Chrome Developer tools error message

If you are familiar with C#, you know there is a compilation warning to prevent this mistake. The TypeScript compiler doesn't provide such option. So, you have to use another solution. Since the version 4.4, TSLint can check your code does not contain floating promise.

Using TSLint to detect floating promises

TSLint is an extensible static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters.

  1. Download TSLint: npm install -g tslint typescript
  2. Configure TSLint:

TSLint provides lots of rules. In this post, we'll only use the one to detect floating promises.

Create a file named tslint.json int the root directory of your project with the following content:

{
    "extends": "tslint:recommended",
    "rules": {
        "no-floating-promises": true
    }
}

Note: If you are using JQuery promises or any other alternative to standard promises, you have to adapt the configuration with something similar to: "no-floating-promises": [true, "JQueryPromise"].

  1. Run tslint: tslint --project tsconfig.json
PS F:\Samples> tslint --project tsconfig.json

ERROR: F:/Samples/index.ts[12, 5]: Promises must be handled appropriately

You can now easily detect where you forgot to await promises thanks to TSLint 😃

BTW, if you actually want the fire and forget behavior, you can disable the tslint rule for a specific line:

// tslint:disable-next-line:no-floating-promises
checkValueAsync(null);

Or you can change the return type of the statement using void:

void checkValueAsync(null);

Conclusion

TSLint is a valuable tool to add to your toolbox. You can easily integrate it in your build pipeline. In this post, I show only one rule of TSLint, but you can activate more than 100 rules to ensure your code is well-written!

Additional links:

Leave a reply