In my application, I have implemented two modules (CAR, BUS) and I want all other related components to be linked with these using an enum. For instance, within a config file, I aim to store configurations for either of the mentioned modules, ensuring that they are always associated with the corresponding module key from the enum. Therefore, the config objects should utilize the module name from the enum as their key.
Here is an example that reflects my current scenario.
enum Vehicles {
CAR = "car",
BUS = "bus"
}
type VehicleKeys = keyof typeof Vehicles;
type VehicleValues = `${Vehicles}`;
interface CarConfig{
engine: string;
};
interface BusConfig{
color: string
}
/**
* {
* car: CarConfig;
* bus: BusConfig;
* }
*/
type VehicleConfig = { [K in VehicleValues]?: CarConfig | BusConfig };
interface Config extends VehicleConfig {
name: string,
}
const config: Config = {
name: "test",
car: {
engine: "My Car",
},
bus: {
color: "Red",
}
}
if(config.car){
console.log( config.car.engine)
}
To ensure that the config keys are limited to the enum keys, I opted for [K in VehicleValues]. This prevents anyone from adding unrelated elements to the config unless they correspond with the enum. However, this creates a challenge when specifying which interface is relevant to each key.
/**
* {
* car: CarConfig;
* bus: BusConfig;
* }
*/
I could choose any of the interfaces, but then accessing values becomes problematic because the compiler cannot determine the type of data.
Property 'engine' does not exist on type 'CarConfig | BusConfig'.
Property 'engine' does not exist on type 'BusConfig'.
Is there a way to enforce restrictions on the keys while also specifying which interface should correspond to its value?
Access the sandbox here