Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend indexed typescript interface

Tags:

typescript

Consider a simple indexed interface:

interface FormData {
    [K: string]: string;
}

That lil' guy works great. But, there is a circumstance where I'd like to allow a property to be an array of strings.

interface AcmeFormData extends FormData {
    foobar: string[];
}

Typescript complains with

Property 'foobar' of type 'string[]' is not assignable to string index type 'string'.

Looking through the docs, it seems like the following should be possible, but also complains.

interface FormData {
    [K: string]: string;
    foobar: string[];
}

It should be noted that I'd like to avoid using a union type ([K: string]: string | string[];) because 99% of the time, the data will always be a single string value and therefore would like to avoid having to type hint.

Is this possible? Or am I trying to abuse Typescript?

like image 409
jbarreiros Avatar asked Oct 16 '25 15:10

jbarreiros


1 Answers

You can do this by using an intersection, instead of using extends. EG:

interface FormData {
    [K: string]: string;
}

type AcmeFormData = FormData & { foobar: string[] };

declare const test: AcmeFormData;

test.foobar       // string[]
test.anythingelse // string

However, this does lead to some issues that you need to be careful around, since now the index signature is no longer accurate. So when typescript infers something using that signature, you need to be aware that it will be wrong:

for (let key in test) {
    // val is inferred to have type string, but be careful!
    // In truth, val will be a string[] for the 'foobar' key,
    // but typescript is no longer aware of that. So this will
    // create a runtime error, but compiles without problems!

    const val = test[key].toLowerCase();
}
like image 99
CRice Avatar answered Oct 18 '25 07:10

CRice



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!