Reputation: 1893
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'
Upvotes: 0
Views: 274
Reputation: 1566
Although this answer doesn't reflect OP's specific implementation as closely as others, if you're looking for a simple typed memoize function, this works:
export function memoized<A, B>(f: (a: A) => B): (a: A) => B {
const cache = new Map()
return a => {
if (!cache.has(a)) {
const b = f(a)
cache.set(a, b)
return b
}
return cache.get(a)
}
}
Upvotes: 0
Reputation: 249536
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.
Upvotes: 2
Reputation: 275809
Type '(...args: Parameters<F>) => ReturnType<F>' is not assignable to type 'F'
Fundamentally ...args
implies any number of arguments, whereas F might take a very specific count.
You don't need Prameters
/ ReturnType
for your use case as (func: F): F
covers external type safety and you don't need internal type safety. Here is the simpler way:
function myMemoize<F extends Function>(func: F): F {
// ...
return function(...args: any[]): any {
//...
return func.apply(null, args)
}
}
Upvotes: 0