Search code examples
typescripttypescript-generics

Enforce that two functions take the same parameter types in TypeScript


I want to create a generic function that takes two functions as parameters and returns a result. I want the types to enforce that both functions have the same signature, but not what that signature is (other than the return type).

I can define the types this way:

type Func<TResult> = (...args: any[]) => TResult;

function foo<TResult>(f: Func<TResult>, g: Func<TResult>): TResult { ... }

Which permits the desired parameters:

function f1(s: string, i: number): boolean { return true; }
function g1(s: string, i: number): boolean { return false; }
foo<boolean>(f1, g1);

Unfortunately it also permits functions with different signatures:

function g2(b: boolean): boolean { return false; }
foo<boolean>(f1, g2);

Is it possible to allow the former call to compile but not the latter?

Note that I want this to work for any parameter list (empty, one parameter, two parameters, etc.), but the parameter types for both functions should match.


Solution

  • You can add another type parameters for the parameters and use tuples in rest parameters to spread it to the function signature. This will ensure the parameter types of the two functions are the same (or at least compatible)

    type Func<TParams extends any[], TResult> = (...args: TParams) => TResult;
    
    function foo<TParams extends any[], TResult>(f: Func<TParams, TResult>, g: Func<TParams, TResult>): TResult {
        return null!
    }
    
    function f1(s: string, i: number): boolean { return true; }
    function g1(s: string, i: number): number { return 0; }
    foo(f1, g1);
    
    
    function g2(b: boolean): boolean { return false; }
    foo(f1, g2);
    

    playground link