1

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.

9
  • Similar but no. My question is why static functions don't implement the index. Not how to implement the index itself. Commented Nov 29, 2019 at 16:53
  • 1
    it does implement StringDoers - no it doesn't. Static properties have nothing to do with implementing interface Commented Nov 29, 2019 at 17:30
  • 2
    @Timmmm I still think it's a duplicate of that question, though. The answer you accepted is misleading. Although not technically wrong it just circumvents the error message. In fact, it is worse than not implementing the interface at all. You could add any static method to your class like public static meth(n: number): string { /* */ } and still have a valid class without any compiler warnings. In that case implementing the interface doesn't add any meaning to it. The real answer is in the question I linked to: you can't implement indexable types in a class the way you want to. Commented Nov 29, 2019 at 17:33
  • Possible duplicate of Implement an indexible interface. Commented Nov 29, 2019 at 17:35
  • Yes it circumvents the error message but isn't that the only option, because Typescript isn't smart enough to know that functions are accessed by [key: string]. What's the difference between MyStringDoers['foo'] and map['foo']? Nothing in terms of the types as far as I can tell. Commented Nov 29, 2019 at 17:54

1 Answer 1

1

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);
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.