Search code examples
typescriptreduxreselect

What is the correct usage of extends Function with Parameters and ReturnType


I'm trying to create my own memoization function for reselect. I had to redefine Parameters and ReturnType to accept extends Function (bug?). The signature for myMemoize is correct however the inner function signature isn't compiling.

import { createSelectorCreator } from "reselect";

type Parameters<T extends Function> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends Function> = T extends (...args: any[]) => infer R ? R : any;

function myMemoize<F extends Function>(func: F): F {
  // ...
  return function(...args: Parameters<F>): ReturnType<F> {
    //...
    return func.apply(null, args)
  }
}

export const createMyMemoizeSelector = createSelectorCreator(myMemoize)

The error:

error TS2322: Type '(...args: Parameters<F>) => ReturnType<F>' is not assignable to type 'F'

Solution

  • The problem is that your new function is not really of the same type as the original. The original might have extra properties, that you do not forward to the return function.

    You can just skip the return type, and also Parameters and ReturnType (both of which are defined so don't redefine them), are not really necessary for a full typed version :

    function myMemoize<P extends any[], R>(func: (...a:P)=> R): (...a:P)=> R {
      // ...
      return function(...args: P): R {
        //...
        return func.apply(null, args)
      }
    }
    

    Not sure how this interacts with createSelectorCreator though.