Why does typescript not allow overriding a function with the exact same Parameters<typeof fn> and ReturnType<typeof fn>?

Viewed 207

I'm trying to wrap my Promise object to implement some kind of generic logging, but Typescript (in strict mode of course) gives me rather hard to digest errors. Here's what I'm trying to do:

function wrapPromise<T>(promise: Promise<T>) {
    const oThen = promise["then"];

    promise["then"] = function (...args: Parameters<typeof oThen>): ReturnType<typeof oThen> {
  //^^^^^^^^^^^^^^^ error here
        // some wrapping code
        const retVal = oThen.apply(promise, args);
        // other wrapping code
        return retVal;
    };
}

The error message:

Type '<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => unknown) | null | undefined, onrejected?: ((reason: any) => unknown) | null | undefined) => Promise<unknown>' is not assignable to type '<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<...>'.
  Type 'Promise<unknown>' is not assignable to type 'Promise<TResult1 | TResult2>'.
    Type 'unknown' is not assignable to type 'TResult1 | TResult2'.
      Type 'unknown' is not assignable to type 'TResult2'.
        'TResult2' could be instantiated with an arbitrary type which could be unrelated to 'unknown'.(2322)

I don't really understand how unknown comes in at all, and I have no idea what the last line in the error message means. For sure it has something to do with the reject function. But if I use the very same parameters and return type, why is the function not assignable?

Update: Even if I'm not using the utility types, I get the exact same error at a different location:

function wrapPromise<T>(promise: Promise<T>) {
    const oThen = promise["then"];

    promise["then"] = function <TResult1 = T, TResult2 = never>(
        onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined,
        onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined)
        : Promise<TResult1 | TResult2>{
        // some wrapping code
        const retVal = oThen.call(promise, onfulfilled, onrejected);
        // other wrapping code
        return retVal;
        //^^^^^^^^^^^ error here
    };
}
0 Answers
Related