I have a set of preferences, defined as an enum of strings:
export enum PreferenceTypes {
language = "language",
unit = "unit",
}
I can then create an interface to define the shape of an expected object. The keys will be the values of the enum:
export type UnitTypes = "µg/m3" | "ppm" | "ppb";
export type LanguageTypes = "English" | "Spanish";
export interface PreferenceOptions {
[PreferenceTypes.language]: {
name: string;
value: LanguageTypes;
}[];
[PreferenceTypes.unit]: {
name: string;
value: UnitTypes;
}[];
}
Now I want to create a default preferences object, based on a user locale. I want the keys of this new object to be the local, and I want the values to be objects. Each object should have keys of type PreferenceTypes, and the values must be the type of value that corresponds to that PreferenceType in PreferenceOptions. I am trying to construct such a type constraint, but I am having a hard time:
PreferenceByLocale: {
[key: string]: { [key in PreferenceTypes]?: string };
} = {
/** Defaults for UK users */
en: {
language: "English",
unit: "µg/m3",
},
/** Defaults for Spain users */
es: {
language: "Spanish",
unit: "µg/m3",
},
/** Defaults for US users */
us: {
language: "English",
unit: "ppm",
},
};
I dont know how to say that the value of each of these objects should really be { [T extends key in PreferenceTypes]?: PreferenceOptions[T]['value'] } - that gives me TS errors. I am not sure if what I'm trying to do is possible, or if I'm overthinking my typing. For example, I should be able to get an error if I wrote something like this:
PreferenceByLocale: {
[key: string]: { [key in PreferenceTypes]?: string };
} = {
/** Defaults for mars users */
mrs: {
// I want this to error, as "Martian" does not exist on LanguageTypes
language: "Martian",
unit: "µg/m3",
},
}
Is such a thing possible?
