Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 674
Sh eldeeb Avatar asked Mar 12 '26 02:03

Sh eldeeb


1 Answers

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.

like image 184
Oblosys Avatar answered Mar 14 '26 15:03

Oblosys