function whatever(object, methodName, args) { return object[methodName](...args); }
Can the above be typed so the the following is enforced:
methodName
is a key of object
.object[methodName]
is callable and its args are ...args
.whatever(object, methodName, args)
is the return type of object[methodName](...args)
.The closest thing I could find is the definition of function.apply
, but it isn't quite the same as the above.
The call() method is a predefined JavaScript method. It can be used to invoke (call) a method with an owner object as an argument (parameter). With call() , an object can use a method belonging to another object.
Yes, but always think carefully whether the function actually needs to be in a class, or should it be a free function altogether.
Parameter Names This name is used within the method body to refer to the passed-in argument. The name of a parameter must be unique in its scope. It cannot be the same as the name of another parameter for the same method or constructor, and it cannot be the name of a local variable within the method or constructor.
Theoretically you can set these max stack size to 8192 bits. Each variable takes up 32 bits then you could pass 256 parameters. 8192/32 = 256. There is no maximum limit to pass parameters or arguments to a user defined function.
I think this does the trick:
function callMethodWithArgs< M extends keyof T, T extends { [m in M]: (...args: Array<any>) => any }, F extends T[M] >(obj: T, methodName: M, args: Parameters<F>) { return obj[methodName](...args) as ReturnType<F>; }
Requires TS 3 though!
type Dictionary = { [key: string]: any } type MethodNames<T extends Dictionary> = T extends ReadonlyArray<any> ? Exclude<keyof [], number> : { [P in keyof T]: T[P] extends Function ? P : never }[keyof T] function apply<T extends Dictionary, P extends MethodNames<T>>( obj: T, methodName: P, args: Parameters<T[P]> ): ReturnType<T[P]> { return obj[methodName](...args); } // Testing object types: const obj = { add: (...args: number[]) => {} } apply(obj, 'add', [1, 2, 3, 4, 5]) // Testing array types: apply([1, 2, 3], 'push', [4]) // Testing the return type: let result: number = apply(new Map<number, number>(), 'get', [1])
Playground link
The Dictionary
type allows T[P]
to be used.
The Parameters
and ReturnType
types are baked into TypeScript.
The MethodNames
type extracts any keys whose value is assignable to the Function
type. Array types require a special case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With