Waterscroll Waterscroll - 6 months ago 27
TypeScript Question

Generic memoize function returning the same function type

I am trying to write a memoize function that takes a function as an argument and returns an alike memoized function.

function memoize<T extends Function, R>(f: T): T {
const memory = new Map<string, R>();

const g = (...args: any[]) => {
if (!memory.get(args.join())) { memory.set(args.join(), f(...args)); }
return memory.get(args.join());
};

return g; // g as T => [ts] Type '(...args: any[]) => R' cannot be converted to type 'T'.
}

// const exp: (...args: any[]) => RegExp
const exp = memoize<(text: string) => RegExp, RegExp>((text: string) => {
return new RegExp(text.replace(/[^a-zA-Z0-9\s]/g, ".").replace(/\s+/g, "\\s+"), "ig");
});


The problem is that if I just return
g
, the signature of exp becomes
(...args: any[]) => RexExp
and if I try to force g to be T, then
ts
complains that g is not assignable to
T
.

Is there a way to "force"
g
to be the same type of
f
in order to
exp
to have the exact same type of the function passed to
memoize
?

Answer Source

This seems to be working:

function memoize<R, T extends (...args: any[]) => R>(f: T): T {
    const memory = new Map<string, R>();

    const g = (...args: any[]) => {
        if (!memory.get(args.join())) {
            memory.set(args.join(), f(...args));
        }

        return memory.get(args.join());
    };

    return g as T;
}

const exp = memoize((text: string) => {
    return new RegExp(text.replace(/[^a-zA-Z0-9\s]/g, ".").replace(/\s+/g, "\\s+"), "ig");
});

(code in playground)