| Expression (p: Promise) |
Correct type |
Current type |
| p.then() |
Promise |
Promise<{}> |
| p.then(b => 1) |
Promise |
Promise |
| p.then(b => 1, e => 'error') |
Promise<number |
string> |
| p.then(b => 1, e => {}) |
Promise<number |
void> |
| p.then(b => 1, e => {throw Error()}) |
Promise |
Promise |
| p.then(b => 1, e => Promise.reject(Error())) |
Promise |
Promise |
| p.catch(e => 'error') |
Promise<boolean |
string> |
| p.catch(e => {}) |
Promise<boolean |
void> |
| p.catch(e => {throw Error()}) |
Promise |
Promise |
| p.catch(e => Promise.reject(Error())) |
Promise |
Promise |
Using overloading and the new never type, PromiseLike/Promise could be typed to handle all these cases correctly:
interface PromiseLike<T> {
then(): PromiseLike<T>;
then<R1>(onfulfilled: (value: T) => R1 | PromiseLike<R1>): PromiseLike<R1>;
then<R1, R2>(onfulfilled: (value: T) => R1 | PromiseLike<R1>,
onrejected: (reason: any) => R2 | PromiseLike<R2>): PromiseLike<R1 | R2>;
}
interface Promise<T> {
then(): Promise<T>;
then<R1>(onfulfilled: (value: T) => R1 | PromiseLike<R1>): Promise<R1>;
then<R1, R2>(onfulfilled: (value: T) => R1 | PromiseLike<R1>,
onrejected: (reason: any) => R2 | PromiseLike<R2>): Promise<R1 | R2>;
catch<R2>(onrejected: (reason: any) => R2 | PromiseLike<R2>): Promise<T | R2>;
}
declare var Promise: {
reject(reason: any): Promise<never>; // Returned promise is never fulfilled
};
Using overloading and the new
nevertype, PromiseLike/Promise could be typed to handle all these cases correctly: