I'm trying to set up a type for a generic function. The second type argument should be inferred from the type of the second function argument.
It's not working, though, I think because of the way the type of the second argument also depends on the first type argument...
It's hopefully much easier to understand what I'm trying to achieve by looking at the code:
export type TypedContract = Contract & {
functions: Record<string, (...args: any[]) => any>;
filters: Record<string, (...args: any[]) => any>;
};
export const useTypedRead = <
C extends TypedContract,
MethodName extends keyof C["functions"]
>(
address: string,
method: MethodName,
params: Parameters<C["functions"][MethodName]>
): void => {
/** */
};
// When calling like this, I get "Expected 2 type arguments, but got 1"
useTypedRead<Erc20>("0xSomeAddress", "balanceOf");
CodePudding user response:
You just have to use default value for next generics like this:
export const useTypedRead = <
C extends TypedContract,
MethodName extends keyof C["functions"] = keyof C["functions"]
>(
address: string,
method: MethodName extends keyof C["functions"] ? MethodName : never,
params: Parameters<C["functions"][MethodName]>
): void => {
/** */
};
CodePudding user response:
If you could also pass the contract object, typescript could infer it all for you. Like so:
export type TypedContract = {
functions: Record<string, (...args: any[]) => any>;
filters: Record<string, (...args: any[]) => any>;
};
export const useTypedRead = <
Contract extends TypedContract,
MethodName extends keyof Contract["functions"]
>(
contract: Contract,
address: string,
method: MethodName,
...params: Parameters<Contract["functions"][MethodName]>
): void => {
/** */
};
const myContract = {
functions: {
balanceOf: (foo: string, bar: string) => void (0)
},
filters: {
foo: () => void (0)
}
}
//this doesn't work
useTypedRead(myContract, "0xSomeAddress", "someFunction");
//this works as expected and we have to pass the two parameters
useTypedRead(myContract, "0xSomeAddress", "balanceOf", "foo", "bar");
CodePudding user response:
Based on your type definition, there are two arguments:
useTypedRead = < Contract extends TypedContract , MethodName extends keyof Contract["functions"]>
but when you called it, you have used only one type:
useTypedRead<Erc20>
Hope this helps!