2

I have this:

type myType = {};

const alpha = (a: string, b:string) => {};
const beta = (a: number, b:number) => {};

export const deploy = async <C extends myType>(toDeployContract: C): C => {}

What I want to achieve is that deploy accept a function as parameter like that:

export const deploy = async <C extends myType>(func: (...args: any[]) => any, toDeployContract: C): C => {}

And that doing so, typed deploy last parameters automatically based on the passed function. Basically copying every parameter of the pass function.

// If alpha function
deploy(alpha, "hello", "world");

// If beta function
deploy(beta, 1, 2);

Is that doable ?

1 Answer 1

2

It's very doable! You will want your deploy function to have a generic type parameter that represents the type of the function. You can make use of the built-in utility types Parameters<T> and ReturnType<T> to get the arguments and return type of the function.

I'm not exactly sure how your C extends myType comes into play here. It seems like it's the return type of the function? You could use C as a second generic type parameter but I would recommend leaving it off.

export const deploy = async <T extends (...args: any[]) => any>(
  func: T, 
  ...args: Parameters<T>
): Promise<ReturnType<T>> => {
    return func(...args);
}

We say that deploy is based on a type T which must be a function. The first argument of deploy is the function T and the remaining arguments are the arguments of that function. deploy returns a Promise which resolves to the return type of the function T.

This allows the usages that you want and gives errors if there is a mismatch between the function and the arguments.

// If alpha function
deploy(alpha, "hello", "world");

// If beta function
deploy(beta, 1, 2);

// Expect error
deploy(alpha, 1, 2); // Argument of type 'number' is not assignable to parameter of type 'string'.(2345)

Typescript Playground Link


If you wanted to use your C type, that might look something like this. We say that T is a function which must return a value that is assignable to C.

type myType = {
    a: string;
};

const alpha = (a: string, b:string) => ({a, b});
const beta = (a: number, b:number) => ({a, b});

export const deploy = async <C extends myType, T extends (...args: any[]) => C>(
  func: T,
  ...args: Parameters<T>
): Promise<C> => {
    return func(...args);
}

The alpha function is still fine because it returns {a: string; b: string;} which extends {a: string}. But you can no longer use the beta function because its return type is not assignable to myType.

So the C parameter allows you to enforce a restriction on what type of function you can deploy with.

Typescript Playground Link

Sign up to request clarification or add additional context in comments.

Comments

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.