Timmmm
Timmmm

Reputation: 96546

Typescript class with static functions that implement an interface with string index

Consider the following code:

interface StringDoers {
  [key: string]: (s: string) => void;
}

class MyStringDoers implements StringDoers {
  public static print(s: string) {
    console.log(s);
  }
  public static printTwice(s: string) {
    console.log(s);
    console.log(s);
  }
}

This gives me a type error:

Class 'MyStringDoers' incorrectly implements interface 'StringDoers'.

Index signature is missing in type 'MyStringDoers'

But from Javascript's point of view, it does implement StringDoers. In a Javascript console I can do this perfectly well:

class MyStringDoers {
    static print(s) {
        console.log(s);
    }
    static printTwice(s) {
        console.log(s);
        console.log(s);
    }
}
MyStringDoers["printTwice"]("hello");

I wondered if it is because [string] can also return undefined, e.g.

MyStringDoers["foo"]; // undefined

However even changing the interface to this does not work:

interface StringDoers {
  [key: string]: ((s: string) => void) | undefined;
}

How can I make this work? The constraint is that StringDoers is in a third party library so I cannot change it. And I want an actual type that knows about all of the methods - i.e. not just:

const doers: StringDoers = {
   print(s: string) {
       console.log(s);
   },
   ...
}

I expect someone who doesn't know the answer will try to make themselves feel better by asking why I'd want to do this, so: my use case is adding proper typing for Vuex's MutationTree.

Upvotes: 1

Views: 160

Answers (1)

Catalyst
Catalyst

Reputation: 3227

It appears you have to annotate the class as accepting string indexes similarly to how its done in the interface (note no concrete function definition):

interface StringDoers {
  [key: string]: (s: string) => void;
}

class MyStringDoers implements StringDoers {
  [key: string]: (s: string) => void;

  public static print(s: string) {
    console.log(s);
  }
  public static printTwice(s: string) {
    console.log(s);
    console.log(s);
  }
}

Upvotes: 1

Related Questions