Inconsistent type on `Thenable.then` overload?

Author: LucretielCreated May 13, 2019Updated May 13, 2019

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

One of the overloads for Thenable.then is:

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

However, consider this example:

typescript
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:

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

Source: stefanpenner/es6-promise