'TypeScript index signature with promises

What is the correct index signature for the following class?

class MyClass {
  [index: string]: Promise<void> | Promise<MyType>; // not working

  public async methodOne (): Promise<void> { ... }
  public async methodTwo (): Promise<MyType> { ... }
}

I want to be able to execute a method on this class using the string name of the method:

myClassInstance[stringNameOfMethodOne]()

There are two TypeScript errors, one on the method definition and one on the usage of the method. The method definition error is:

Property 'methodOne' of type '() => Promise<void>' is not assignable to 'string' index type 'Promise<void> | Promise<MyType>'

The error on the usage of the method is:

This expression is not callable. No constituent of type 'Promise<MyType> | Promise<void>' is callable.

I've done this in JavaScript but am less familiar with TypeScript's index signatures.



Solution 1:[1]

You probably just forgot the function type:

class MyClass {
  [index: string]: () => (Promise<void> | Promise<MyType>); // A function type returning a Promise

  public async methodOne (): Promise<void> { ... }
  public async methodTwo (): Promise<MyType> { ... }
}

Solution 2:[2]

You may not want an index signature at all. Because this works fine:

interface MyType { myType: true }

class MyClass {
  public async methodOne (): Promise<void> {}
  public async methodTwo (): Promise<MyType> { return { myType: true } }
}

const stringNameOfMethodOne = 'methodOne'
const myClassInstance = new MyClass()
myClassInstance[stringNameOfMethodOne]() // works

stringNameOfMethodOne here is actually a string literal type, so typescript knows exactly what property it will look up, which makes everything work.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ghybs
Solution 2 Alex Wayne