Typescript 映射类型 - 枚举值作为键,接口对应的值作为值

Typescript mapped types - enum value as key, and interface's corresponding value as value

我有一组首选项,定义为字符串枚举:

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

然后我可以创建一个界面来定义预期对象的形状。键将是枚举的值:

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;
    }[];
}

现在我想创建一个基于用户语言环境的默认首选项对象。我希望这个新对象的键是本地的,我希望值是对象。每个对象都应该有 PreferenceTypes 类型的键,值必须是 PreferenceOptions 中对应 PreferenceType 类型的 value 类型。我正在尝试构建这样的类型约束,但我遇到了困难:

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",
    },
};

我不知道如何说这些对象中的每一个的值实际上应该是 { [T extends key in PreferenceTypes]?: PreferenceOptions[T]['value'] } - 这给了我 TS 错误。我不确定我正在尝试做的事情是否可行,或者我是否正在考虑我的打字。例如,如果我这样写,我应该能够得到一个错误:

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",
    },
}

这样的事情可能吗?

你的错误是:在定义PreferenceOptions时,每个属性的值都是一个数组。仔细检查下面的代码:

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

您需要知道,在 TypeScript 中,如果您将 [] 添加到值的末尾,它会将其定义为数组。所以下面两段代码给出了相同的结果:

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

所以您所要做的就是更改 PreferenceOptions 如下:

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

现在试试这个:

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)

将给出以下结果:

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

好的,我想我现在更清楚你想做什么了。我做了这样的修改。

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);

现在它为夫人给出以下错误:

我想这就是你想要做的。如果那是你想做的并且代码很难理解,我可以解释。