Reputation: 537
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 ?
Upvotes: 2
Views: 714
Reputation: 42188
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)
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.
Upvotes: 2