Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a member of an object with arguments

Tags:

typescript

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.
  • The return type of 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.

like image 976
JaffaTheCake Avatar asked Jan 10 '19 13:01

JaffaTheCake


People also ask

What is Call () in JavaScript?

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.

Can a member function defined within an object definition takes zero arguments?

Yes, but always think carefully whether the function actually needs to be in a class, or should it be a free function altogether.

Can the argument have the same name as its parameter?

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.

How many parameters can you add to a function?

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.


2 Answers

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!

like image 127
richsilv Avatar answered Oct 04 '22 04:10

richsilv


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.

Checklist

  • Method name is validated? ✅
  • Arguments are type-checked? ✅
  • Return type is correct? ✅
like image 28
aleclarson Avatar answered Oct 04 '22 02:10

aleclarson