0

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?

2 Answers 2

1

Ok, I think I understand better what you want to do now. I made a revision like this.

export enum PreferenceTypes {
language = "language",
unit = "unit",
}

export type UnitTypes = "µg/m3" | "ppm" | "ppb";
export type LanguageTypes = "English" | "Spanish";

export interface PreferenceOptions {
[PreferenceTypes.language]: LanguageTypes;
[PreferenceTypes.unit]: UnitTypes;
}

export interface PreferenceByLocale {
[key : string]: PreferenceOptions;
}

const PreferenceByLocale: PreferenceByLocale = {
/** 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",
},
mrs: {
    language: "Unkown",
    unit: "sxsx"
  }
 };

 console.log(PreferenceByLocale);

now it gives the following error for mrs:

enter image description here

I guess that's what you wanted to do. If that's what you want to do and the code is hard to understand, I can explain.

Sign up to request clarification or add additional context in comments.

Comments

0

Your mistake is: When defining PreferenceOptions, the value of each property is an array. Examine the code below carefully:

export interface PreferenceOptions {
[PreferenceTypes.language]: {
    name: string;
    value: LanguageTypes;
}[];
[PreferenceTypes.unit]: {
    name: string;
    value: UnitTypes;
}[];
}

Your need to know, in TypeScript if you add [] to the end of a value it defines it as an array. So the following two blocks of code give the same result:

let names : Array<string> = [];
let names : string[] = [];

So all you have to do is to change the PreferenceOptions as below:

export interface PreferenceOptions {
[PreferenceTypes.language]: {
    name: string;
    value: LanguageTypes;
};
[PreferenceTypes.unit]: {
    name: string;
    value: UnitTypes;
};
}

and now try this:

const 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",
},
};
console.log(PreferenceByLocale)

will give the following result:

{
   en: { language: 'English', unit: 'µg/m3' },
   es: { language: 'Spanish', unit: 'µg/m3' },
   us: { language: 'English', unit: 'ppm' }
}

1 Comment

Nice catch. My issue is that I actually do need those values to be arrays...is there a better way to organize all this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.