4

I have a class that can be extended by the user like this:

class Foo {
   extendFoo(key: string, value: string) {
      this[key] = value; //<==typescript error: missing index signature
   }
}

as you can see, this can be extended with strings. the problem is that typescript complains because I don't have an index signature, so I tried to add one:

class Foo {
   [key: string]: string;

   extendFoo(key: string, value: string) {  //<==typescript error: extendFoo is not a string
      this[key] = value;
   }
}

how can I add the index signature, but still allow methods in my class?

of course I can change the index signature to be [key: string]: string | Function, but it's not correct- any unknown key must be a string. how can I exclude only extendFoo from the index signature?

class Foo {
   [key: string]: string | Function;

   extendFoo(key: string, value: string) {
      this[key] = value;
   }
}

const test = new Foo();
test['some unknown prop'].includes('test'); //<== typescript error: 'Property 'includes' does not exist on type 'Function'

BTW, I know it is a bad pattern to extend this, but I am converting a legacy code to typescript and have no choice.

niryo
  • 1,275
  • 4
  • 15
  • 26
  • 1
    Does this answer your question? [Typescript index signature and methods](https://stackoverflow.com/questions/55054226/typescript-index-signature-and-methods) – DAG Mar 16 '20 at 14:21
  • Does [this](http://www.typescriptlang.org/play?#code/MYGwhgzhAEBiD29oG8CwAoaXoFMAeALjgHYAmC8APACq6EmkwUA00A0nUWTBAQE4BLYgHMAfAAoCACwEQAXNGqsA1jgCeCgKJ5QAV1I5KbFevgAzRaNYA3MCF04FvQSICUCyBBx8CMabOgA2gAyFGgAbQAFQOJ2AF0nfiFhaABfFAxsLOh-CHDVNWhIaALzRTjoAF5oW3scIpgwYjUAbmgAenboYhwcUhykT28CTOxUjHH0DGB4Yl5oMwUKKu6cAHc4RHFXNs7VvoGi4mJ4AjAiDDMAOnwuci2AIgAjMD4H1gfah53Lq5e+K5CPQGCDiB5gb4tX7-FYPeDKMBqB5Q9DXW4MChgl4AL3e0E+dgATJDoWBsbDeAIQCBoPDEcjfgBHXR4WEnAAOOGRHS63j48D4rBO0GZeF+6LImIeorxBJAAGYSairqLYXTCmBhGAhAzlRL7vAsa9ZRyuTsebg+PzBdBgE0AOQEaB8HAAWn10AgYAAtvUChggA) work for you? If so I'll write it up. – jcalz Mar 16 '20 at 14:53
  • @DaGardner, I stumbled upon this link before I asked the question, but it's not good for my case. the suggested solution is what I have in my third code snipped, and i explained why it isn't good enough for me. – niryo Mar 16 '20 at 15:46
  • @jcalz, this is an interesting solution. how can you send the link in the comments? it's too long, i wan't to share it with you – niryo Mar 16 '20 at 15:58

1 Answers1

0

I don't think TS is able to do exactly what you want in a fully type-safe way since the type of a key needs to be string or number. As your methods are known and exceptional it might be ok to @ts-ignore the TS error?

class Foo {
    [key: string]: string | null;

    // @ts-ignore
   extendFoo(key: string, value: string) {
      this[key] = value;
   }
   // @ts-ignore
}


const test = new Foo();
test['some unknown prop']?.includes('test'); // <- No error
test.extendFoo("asdf", "asdf"); // <- works, too

I know it's not ideal but at least you won't have to cast on every call site.

mfeineis
  • 2,607
  • 19
  • 22