[typescript] Returning a promise in an async function in TypeScript

It's my understanding that these two functions will have the same behavior in JavaScript:

const whatever1 = (): Promise<number> => {
    return new Promise((resolve) => {
        resolve(4);
    });
};

const whatever2 = async (): Promise<number> => {
    return new Promise((resolve) => {
        resolve(4);
    });
};

But TypeScript seems to not like the second one, it says:

Type '{}' is not assignable to type 'number'.

Is this a bug in TypeScript, or am I misunderstanding something about async functions?

This question is related to typescript

The answer is


It's complicated.

First of all, in this code

const p = new Promise((resolve) => {
    resolve(4);
});

the type of p is inferred as Promise<{}>. There is open issue about this on typescript github, so arguably this is a bug, because obviously (for a human), p should be Promise<number>.

Then, Promise<{}> is compatible with Promise<number>, because basically the only property a promise has is then method, and then is compatible in these two promise types in accordance with typescript rules for function types compatibility. That's why there is no error in whatever1.

But the purpose of async is to pretend that you are dealing with actual values, not promises, and then you get the error in whatever2 because {} is obvioulsy not compatible with number.

So the async behavior is the same, but currently some workaround is necessary to make typescript compile it. You could simply provide explicit generic argument when creating a promise like this:

const whatever2 = async (): Promise<number> => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

When you do new Promise((resolve)... the type inferred was Promise<{}> because you should have used new Promise<number>((resolve).

It is interesting that this issue was only highlighted when the async keyword was added. I would recommend reporting this issue to the TS team on GitHub.

There are many ways you can get around this issue. All the following functions have the same behavior:

const whatever1 = () => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever2 = async () => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever3 = async () => {
    return await new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever4 = async () => {
    return Promise.resolve(4);
};

const whatever5 = async () => {
    return await Promise.resolve(4);
};

const whatever6 = async () => Promise.resolve(4);

const whatever7 = async () => await Promise.resolve(4);

In your IDE you will be able to see that the inferred type for all these functions is () => Promise<number>.