3

For example, suppose I'm writing a memoize function, which accepts a function and returns another function. I want to leverage TypeScript so that the output function is guaranteed to have the same type as the input function, even though I don't know the type of the input function in advance. Here's some example code:

function wrap(fn) {
  return function(...args) {
    return fn(...args);
  };
}

function repeat1(a: string, b: number): string {
  return a.repeat(b);
}

const repeat2 = wrap(repeat1);

Unfortunately, repeat2 resolves to the type (...args: any[]) => any. I can't seem to find a way to express the wrap function in such a way that propagates the input type to the output type.

1 Answer 1

4

You need to use generics and Tuples in rest parameters and spread expressions

function wrap<A extends any[], R>(fn: (...a: A) => R) {
  return function(...args: A) {
    return fn(...args);
  };
}

function repeat1(a: string, b: number): string {
  return a.repeat(b);
}

const repeat2 = wrap(repeat1); // inferred to const repeat2: (a: string, b: number) => string

The above version does not work for generic functions. We can create a version that preserves generic function arguments if we forgo any implementation type safety (this is an acceptable trade-off as we get better call site safety which is more important)

function wrap<T extends Function>(fn: T): T {
    return function(...args: any[]) :any {
        return fn(...args);
    } as any;
}

wrap(<T>(x: T): T => x)
Sign up to request clarification or add additional context in comments.

4 Comments

It works for the above case, but this: wrap(<T>(x: T): T => x) "forgets" the input type and resolves to (...args: any[]) => any. (Which I see mentioned in the caveats)
@greim Added a version that plays better with generics
This works, though it seems kind of hacky. Is it safe to say that TypeScript doesn't yet support fully generic functional programming?
@greim I guess the answer is not 100%. You can get it to work 100% for the call site, but the implementation will require some type assertions. The good news is implementations are written once and used many time so it's better than nothing :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.