Q:

Typescript - Has no index signature when use Enums as index signature types

I have the follow type structure:
export type Method1 = (id: string, param: string) => Promise<any>

export enum ValuesList {
  VALUE1 = 'VALUE1',
  VALUE2 = 'VALUE2'
}

export type ValuesMap = {
  [key in ValuesList]: {
    callMethod: Method1
  }
}

export const methodsMap: ValuesMap = {
  [ValuesList.VALUE1]: {
    callMethod: lib.method
  },
  [ValuesList.VALUE2]: {
    callMethod: lib2.method
  }
}

And in some part of the application I want to map some list to call this method dynamically:
methodsMap[target].callMethod(data.id, data.param)

By typescript are returning the follow problem:
Element implicitly has an 'any' type because type 'ValuesMap' has no index signature.ts(7017)

Typescript are not recognise ValuesMap as an element with a index. If I change the ValuesMap to use [key: string] instead of [key in ValuesList] it works, but I would like to keep the [key in ValuesList]

A:

First, let's recap some terminology. In TypeScript, index signature can be either a string or a number, but nothing narrower. If you, instead of using just the string type, explicitly specify the type via a literal, that's called a property, not an index signature. That's why enums never have a type signature but do have properties.
type A = {
   [key: string]: number // this is index signature
};

type B = {
   [key in 'foo' | 'bar']: number // this is a property 
}

Now to the actual code. The snippet you posted seems to be working just fine. When you leave your mouse over the name ValuesMap, a tooltip will show you that it is:
type ValuesMap = { VALUE1: { callMethod: Method1; }; VALUE2: { callMethod: Method1; }; }

So, indeed, it contains the two values from the Enum. The problem therefore has to be the target you're using as an index. Because TypeScript is complaining about seeing no index signature, my best guess is that the target you're using is of type string, therefore possibly not a value of that enum. (You can hover your mouse above it to see its type.) Since TypeScript wants to protect you from calling the callMethod on undefined, it starts yelling at you until you restrict target to the correct values.

