Reputation: 2186
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
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; }'.
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