stefanpenner / es6-promise

A polyfill for ES6-style Promises
MIT License
7.3k stars 593 forks source link

Inconsistent type on `Thenable.then` overload? #347

Open Lucretiel opened 5 years ago

Lucretiel commented 5 years ago

https://github.com/stefanpenner/es6-promise/blob/9869a4bc92c0372b9fc9e2dc3a9a1a861d91bbe0/es6-promise.d.ts#L3

One of the overloads for Thenable.then is:

then <U> (
    onFulfilled?: (value: R) => U | Thenable<U>,
    onRejected?: (error: any) => void,
): Thenable<U>;

However, consider this example:

let promise = Promise<number>.reject(new Error("error"));

let newPromise = promise.then(
    (value: number): string => value.toString(),
    (error: any): void => { console.log(error); },
);

The type of newPromise, based on the overload, is Promise<string>. However, because the onRejected function doesn't throw or return a rejected promise, newPromise becomes a resolved promise with the return value of onRejected, which is void, which means that newPromise should be Promise<T | void>. Specifically, this code should not compile:

newPromise.then((value: string) => {
    // value should be `(string | void)`, since it could have a
    //value from the `onRejected` branch
});
Lucretiel commented 5 years ago

See also: https://github.com/microsoft/TypeScript/blob/master/src/lib/es5.d.ts#L1379-L1394