Typescript: how can I exclude methods from the index signature of classes?

541 Views Asked by At

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.

1

There are 1 best solutions below

0
On

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.