I have a rather complex interface that will have many well known instances. These instances should be referable by some kind of ID. Ideally I would like to define all of these well known instances in an object so that I can use the keyof operator to trivially have a type for the key.
interface Complex {
frobs: number[];
type: 'A' | 'B';
} // More complicated in reality
const COMMON = {
foo: { type: 'A', frobs: [] }, // this is fine
bar: { type: 'B', frobs: [1], zorg: 1 }, // unwanted extra
baz: { type: 'A', noFrobs: "uh-oh" }, // frobs missing
}
Type CommonId = keyof typeof COMMON; // Great, valid Ids are "foo" | "bar" | "baz"
But if I specify the object without any type (as above), Typescript of course doesn't enforce that all values in that object should be of the same type.
So I wanted to specify that all values must be of type Complex but I couldn't do so without specifying the key type. And now I have to mention every key twice: Once as part of the CommonId and once in the object:
interface Complex {
frobs: number[];
type: 'A' | 'B';
} // More complicated in reality
type CommonId = "foo" | "bar"; // Much more common objects in reality
const COMMON: {
[commonId in CommonId]: Complex
} = {
foo: { type: 'A', frobs: [] },
bar: { type: 'B', frobs: [1] }
}
Is there a way to get the best of both worlds? I would love to just extend the COMMON variable with a new key-value pair to automatically add that key to the CommonId type.