I am trying to build a generic type that extracts from a complex object all the function which take a specified set of arguments, where the arguments might not always be the same type (Playground link):
type FunctionPropertyNames<T, FnArgs extends TupleType = TupleType, R = any> = {
//ts(2370) error on next line: A rest parameter must be of an array type.
[K in keyof T]: T[K] extends ((...args: FnArgs) => R) ? K : never
} [keyof T];
A function in a file I'm converting from JavaScript takes in T
, a subset of these function property names (in an array), and the tuple which is the common set of parameters to call all the named functions with. (Some settings also have a need to filter out function properties that have a particular return type, motivating parameter R.) If a type definition like this worked, it could be used to limit the set of possible function names to be called, eliminating a type issue there.
The stated error seems incorrect to me; my understanding is that tuple type could be used in this setting, but the error says I'm wrong on that. It seems quite possible I'm still making some syntax mistake with TupleType
and maybe there's some better way to express this (possibly involving curly braces) which I just can't figure out. If someone reading this can spot the error and point it out, that might be helpful not only to me but others who might come along later.
CodePudding user response:
Don't use the TupleType of typescript, use any[] instead. If you want to access the arguments or the return type, try to infer it
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: infer Args) => infer Return ? { [U in K]: { args: Args, return: Return } } : never
}[keyof T];
type FunctionPropertyNames_<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never
}[keyof T];
type x = FunctionPropertyNames<{ test: (a: number, b: string) => string }>
//type x = {
// test: {
// args: [a: number, b: string];
// return: string;
// };
//}
type z = FunctionPropertyNames_<{ test: (a: number, b: string) => string }> //"test"