Imagine a scenario where we have a basic interface:
interface Schedule {
interval: "month" | "day";
price: number;
}
We can create a template-literal type with TypeScript version 4.4:
type PrefixedScheduleKey = `schedule__${keyof Schedule}`; // "schedule__interval" | "schedule__price"
If there are multiple interfaces like this and we want to combine (essentially flatten) their prefixed, template-literal keys into something like this:
interface Metadata {
foo: string;
bar: string;
// computed
schedule__interval: "month" | "day";
schedule__price: number;
...
}
How do we define such interface keys?
interface Metadata {
[key: PrefixedScheduleKey]: any
}
// This throws an error
// An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.(1337)
Also,
interface Metadata {
[key in `schedule__${keyof Schedule}`]: any
}
// Results in
// A computed property name must be of type 'string', 'number', 'symbol', or 'any'.(2464)
// Member '[key in `schedule__${keyof' implicitly has an 'any' type.(7008)
You can test this on the playground.
By the way, it was mentioned on GitHub that using type
instead of interface
is recommended, but in our case, Metadata
already extends another interface so we stuck with using interface
for simplicity.