Pierre-Louis Lacorte
Pierre-Louis Lacorte

Reputation: 363

Type object parameter based on another generic parameter

I'm trying to dynamically type a parameter based on another generic parameter in typescript.

This is to build a custom test framework that takes as parameter the method to test, its arguments and expected result.

// function that tests if the method return an expected result 
const myCustomTest = (arg: { method: (...arg: any[]) => any, arguments: any, response: any }) => {
    const { method, arguments, response } = arg;
    return method.apply(null, arguments) === response; // suppose this is a sync function
};

// given a function test1
const test1 = (arg: number, arg2: boolean): boolean => {
    return true;
};

// then the linter should raise
myCustomTest({ method: test1, arg: [12, 12], response: true }); // wrong, second parameter is a number and not a boolean
myCustomTest({ method: test1, arg: [12, false], response: true }); // OK

// It could work with
type Arguments<T> = T extends (...args: infer U) => any ? U : any;

const myCustomTest = (arg: { method: (...arg: any[]) => any, arguments: Arguments<typeof test1>, response: ReturnType<typeof test1> }) => {
    const { method, arguments, response } = arg;
    return method.apply(null, arguments) === response; // suppose this is a sync function
};

But I would like to find a way to type arguments and response depending on the argument of the method passed in parameter.

Thank you in advance!

Upvotes: 1

Views: 78

Answers (1)

DAG
DAG

Reputation: 6994

Your were really close to the solution! With some minor tweaks this compiles and type checks. You have to make sure to add a generic type paramter to your myCustomTest function:

type Arguments<T> = T extends (...args: infer U) => any ? U : never;

const myCustomTest = <T extends (...args: any) => any>(arg: { method: T, parameters: Arguments<T>, response: ReturnType<T>}) => {
    const { method, parameters, response } = arg;
    return method.apply(null, parameters) === response; // suppose this is a sync function
};

See a full example in this Typescript Playground!

Upvotes: 1

Related Questions