Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does TypeScript not ensure a Promise is resolved with the correct type?

Tags:

typescript

This compiles without error in TypeScript 2.1.5:

function promiseANumber(): Promise<number> {
    return new Promise(resolve => resolve('definitely not a number'));
}

I would expect an error to be reported, since the resolve function is called with a string instead of a number, as per the type definition.

Why is this type mismatch not caught and reported by TypeScript's compiler?


Edit 1

Looking at this a bit more, using an async function definition instead, the compiler correctly reports the type mismatch. So this:

async function promiseANumber(): Promise<number> {
    return 'definitely not a number';
}

gives

error TS2322: Type '"definitely not a number"' is not assignable to type 'number'.

Why do these cases behave differently?


Edit 2

It looks like the way to make the compiler correctly catch this it to explicitly tell it which type of promise you're returning. So this is sufficient:

function promiseANumber() {
    return new Promise<number>(resolve => resolve('definitely not a number'));
}

which the compiler now complains about:

error TS2345: Argument of type '"definitely not a number"' is not assignable to parameter of type 'number | Thenable<number>'.

I suppose my question is now, why can't the compiler infer this, given the definition I gave at the beginning of this question?


Edit 3

Happily, TypeScript 2.4 now indicates the correct error for my original code! It's due to it now supporting return types as inference targets. That announcement even has a code sample very similar to the example I gave initially.

like image 260
markrian Avatar asked Jan 19 '17 17:01

markrian


1 Answers

In this case...

function promiseANumber(): Promise<number> {
    return new Promise(resolve => resolve('definitely not a number'));
}

...the reason why resolve does not expect number is because it's specified as being {} when writing new Promise(...) because that's the default type of new Promise(). The compiler then allows the assignment for Promise<{}> to Promise<number>... that itself is questionable.

In this case...

async function promiseANumber(): Promise<number> {
    // type returned is Promise<string>, doesn't match Promise<number>
    return 'definitely not a number';
}

...the type returned is Promise<string> and that doesn't match Promise<number> so the compiler throws an error.


In your example with the promise, you can tell the compiler to define the promise as Promise<number> by doing:

function promiseANumber(): Promise<number> {
    return new Promise<number>(resolve => resolve('definitely not a number'));
}

...which will cause a compile error because string is not assignable to number.

like image 181
David Sherret Avatar answered Sep 20 '22 02:09

David Sherret