javascript 确保常量(只读)对象的键符合TypeScript中的值或类型的常量(只读)数组

dhxwm5r4  于 2023-04-19  发布在  Java
关注(0)|答案(2)|浏览(138)

假设我有一个对象,我想确保它的键符合另一种类型。我正在创建一个Map键的字典,左边是原始的,右边是显示的键。我需要在运行时和编译时都可以使用它,所以作为const对象和数组来做这件事似乎是有意义的?
(Yes,我尝试用一个元组数组来做这件事,但是TypeScript现在对我很生气)。

const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;

const keyMap = {
   cheese_type:  "Cheese type",
   jalapeno_qty: "Number of jalapeños",
   pepperoni: "Pepperoni",
} as const;

这给了我一个类型,它显式地Map了所有的键:

const keyMap: {
    readonly cheese_type: "Cheese type";
    readonly jalapeno_qty: "Number of jalapeños";
    readonly pepperoni: "Pepperoni";
}

(我也可以导出类型)

export const Keys = typeof allowedKeys
export const KeyMap = typeof keyMap

但是我也想保护keyMap不被意外地拼错或添加不应该有的键,所以我想使它符合allowedKeys数组。
但是如果我这样做了,我就不知道如何将对象值推断或定义为readonly/const属性……

const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;
type Keys = typeof allowedKeys;

const keyMap: {
  [key in Keys]: string // oh no
} = {
   cheese_type:  "Cheese type",
   jalapeno_qty: "Number of jalapeños",
   pepperoni: "Pepperoni",
} as const;

有没有什么方法可以做到这一点,不会让我陷入疯狂的循环,比如:

const keyMap: {
  [key in Keys]: key in keyMap ? keyMap[key] : never; // haha no
} = {
   cheese_type:  "Cheese type",
   jalapeno_qty: "Number of jalapeños",
   pepperoni: "Pepperoni",
} as const;

(最终,我希望能够有两套我可以参考的密钥...)

export type RawKey = typeof keyMap;
export type DisplayKey = ValueOf<typeof keyMap>;
sdnqo3pr

sdnqo3pr1#

您可以使用satisfies操作符来检查值是否与特定类型匹配,而无需将其扩展到可能会丢弃所需信息的类型。
所以只要你有Keys类型的键,你就可以允许:

const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;
type Keys = typeof allowedKeys[number];

你可以说keyMapsatisfies Record<Keys, string>

const keyMap = {
    cheese_type: "Cheese type",
    jalapeno_qty: "Number of jalapeños",
    pepperoni: "Pepperoni",
} as const satisfies Record<Keys, string>;

然后keyMap仍然记住其属性的所有文字类型:

/* const keyMap: {
    readonly cheese_type: "Cheese type";
    readonly jalapeno_qty: "Number of jalapeños";
    readonly pepperoni: "Pepperoni";
} */

如果你在keyMap上犯了错误,编译器应该会捕捉到它们:

const extraKeyMap = {
    cheese_type: "Cheese type",
    jalapeno_qty: "Number of jalapeños",
    pepperoni: "Pepperoni",
    pineapple: "🍍⁉" // error!
} as const satisfies Record<Keys, string>;

const missingKeyMap = {
    cheese_type: "Cheese type",
    pepperoni: "Pepperoni",
} as const satisfies Record<Keys, string>; // error!

const misspelledKeyMap = {
    cheese_type: "Cheese type",
    jalapeno_qty: "Number of jalapeños",
    peppperroni: "Preppypony", // error!
} as const satisfies Record<Keys, string>;

Playground链接到代码

0yycz8jy

0yycz8jy2#

您可以:

const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;
    type Keys = typeof allowedKeys;
    const keyMap: Record<Keys[number], string> = {
        cheese_type:  "Cheese type",
        jalapeno_qty: "Number of jalapeños",
        pepperoni: "Pepperoni"
    } as const;

这将防止向keyMap添加其他密钥。
编辑:关于粉红色的评论,你可以这样做

const keyMap: Readonly<Record<Keys[number], string>> = ...

keyMap设为只读。

相关问题