How could 'F' be instantiated with a different subtype of constraint '(…a: Parameters<F>) => number'?

If the return value derives its rest parameter type from F, how could F be instantiated with a different subtype?

function wrap<F extends (...a: Parameters<F>) => number>(f: F): F {
  return (...a: Parameters<F>) => f(...a)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
Type '(...a: Parameters<F>) => number' is not assignable to type 'F'.
  '(...a: Parameters<F>) => number' is assignable to the constraint of type 'F', but 'F' could be instantiated with a different subtype of constraint '(...a: Parameters<F>) => number'.

>Solution :

Functions in JavaScript are objects and are therefore allowed to have properties like other objects. And just like T extends {a: string}, is allowed to have more properties than just a, F extends (...a: any) => any is allowed to have more properties than just those found on Function.prototype:

function magicFunction(x: string, y: number) {
    return x.length + y;
}
magicFunction.magic = "abracadabra!!";

Or equivalently

const magicFunction = Object.assign(
  (x: string, y: number) => x.length + y, 
  { magic: "abracadabra!!" }
);

So the type of magicFunction is

// const magicFunction: ((x: string, y: number) => number) & { magic: string; }

which has a magic property of type string.


The call signature of wrap() claims to return the same exact type as its argument:

const wrappedMagicFunction = wrap(magicFunction);
// const wrappedMagicFunction: typeof magicFunction

But the implementation only returns a function of type ((x: string, y: number) => number):

console.log(wrappedMagicFunction("abcde", 8)) // 13, okay

And not necessarily a function of the same type as the input; in particular, it does not have the requisite magic property:

console.log(wrappedMagicFunction.magic.toUpperCase()); // compiles okay, but
// 💥 RUNTIME ERROR! wrappedMagicFunction.magic is undefined

Since the implementation cannot be verified to satisfy the call signature, the compiler complains.

Playground link to code

Leave a Reply