Sherif eldeeb
Sherif eldeeb

Reputation: 2186

use variable as a method in typescript

I want to dynamically call methods by a variable name in typescript, as shown in the following example.

function callMethod(_class, method: string){
  let classObj = new _class();
  return classObj[method]()
}

the previous code snippet has no real benefits, but it can obviously explain the idea with a minimal code.

however, if you enabled the option noImplicitAny in tsconfig.json, you have to add a type annotation

return classObj[method as keyof typeof classObj]()

Theoretically, it works fine in Js, but ts complains that not all constituents are callable, and shows this error:

This expression is not callable.
  Not all constituents of type ... are callable.

how can I dynamically call a method in typescript?

Upvotes: 3

Views: 1037

Answers (1)

Oblosys
Oblosys

Reputation: 15106

If you make the method, the class, and the static part of the class all generic, you can do something like this:

function callMethod<
  M extends PropertyKey,
  C extends {[K in M]: () => any},
  T extends {new(): C}
>(_class: T, method: M): ReturnType<InstanceType<T>[M]> {
  const classObj = new _class();

  return classObj[method]() 
}

class Test {
    someMethod(): number { return 8}
}

const t1 = callMethod(Test, 'someMethod') // Inferred type: number.

const t2: string = callMethod(Test, 'someMethod')
// ERROR: .. Type 'number' is not assignable to type 'string'.

const t3 = callMethod(Test, 'noMethod')
// ERROR: .. Property 'noMethod' is missing in type 'Test' but required in
//        type '{ noMethod: () => unknown; }'.

TypeScript playground

Inside callMethod the return type of method will be any, but typing this to a fourth type parameter and getting it to agree with ReturnType<InstanceType<T>[M]> seems tricky (and might not be possible). As long as you directly return the result of the method call, this shouldn't be too much of an issue though.

Upvotes: 2

Related Questions