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

bra*_*ipt 2 javascript generics typescript typescript-generics

假设我有一个对象,我想确保它的键符合另一种类型。我正在创建映射键的字典,其中左侧是原始键,右侧是显示的键。我需要在运行时和编译时都可用它,因此将其作为const对象和数组执行似乎有意义吗?

\n

(是的,我尝试使用元组数组执行此操作,但 TypeScript 现在对我很生气)。

\n
const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;\n\nconst keyMap = {\n   cheese_type:  "Cheese type",\n   jalapeno_qty: "Number of jalape\xc3\xb1os",\n   pepperoni: "Pepperoni",\n} as const;\n
Run Code Online (Sandbox Code Playgroud)\n

这给了我一个明确映射所有键的类型:

\n
const keyMap: {\n    readonly cheese_type: "Cheese type";\n    readonly jalapeno_qty: "Number of jalape\xc3\xb1os";\n    readonly pepperoni: "Pepperoni";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

(我也可以导出类型)

\n
export const Keys = typeof allowedKeys\nexport const KeyMap = typeof keyMap\n
Run Code Online (Sandbox Code Playgroud)\n

但我也想防止keyMap意外拼写错误或添加不应该有的键,所以我想让它符合数组allowedKeys

\n

但如果我这样做,我无法弄清楚如何推断或定义对象值作为只读/常量属性......

\n
const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;\ntype Keys = typeof allowedKeys;\n\nconst keyMap: {\n  [key in Keys]: string // oh no\n} = {\n   cheese_type:  "Cheese type",\n   jalapeno_qty: "Number of jalape\xc3\xb1os",\n   pepperoni: "Pepperoni",\n} as const;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
const keyMap: {\n  [key in Keys]: key in keyMap ? keyMap[key] : never; // haha no\n} = {\n   cheese_type:  "Cheese type",\n   jalapeno_qty: "Number of jalape\xc3\xb1os",\n   pepperoni: "Pepperoni",\n} as const;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
export type RawKey = typeof keyMap;\nexport type DisplayKey = ValueOf<typeof keyMap>;\n
Run Code Online (Sandbox Code Playgroud)\n

jca*_*alz 5

您可以使用运算satisfies来检查值是否与特定类型匹配,而无需将其扩展到该类型,否则会丢弃您想要的信息。

\n

因此,只要您拥有Keys想要允许的密钥类型:

\n
const allowedKeys = ["cheese_type", "jalapeno_qty", "pepperoni"] as const;\ntype Keys = typeof allowedKeys[number];\n
Run Code Online (Sandbox Code Playgroud)\n

你可以这么说吧keyMap satisfies Record<Keys, string>

\n
const keyMap = {\n    cheese_type: "Cheese type",\n    jalapeno_qty: "Number of jalape\xc3\xb1os",\n    pepperoni: "Pepperoni",\n} as const satisfies Record<Keys, string>;\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
/* const keyMap: {\n    readonly cheese_type: "Cheese type";\n    readonly jalapeno_qty: "Number of jalape\xc3\xb1os";\n    readonly pepperoni: "Pepperoni";\n} */\n
Run Code Online (Sandbox Code Playgroud)\n

如果你犯了错误keyMap,编译器应该捕获它们:

\n
const extraKeyMap = {\n    cheese_type: "Cheese type",\n    jalapeno_qty: "Number of jalape\xc3\xb1os",\n    pepperoni: "Pepperoni",\n    pineapple: "\xe2\x81\x89" // error!\n} as const satisfies Record<Keys, string>;\n\nconst missingKeyMap = {\n    cheese_type: "Cheese type",\n    pepperoni: "Pepperoni",\n} as const satisfies Record<Keys, string>; // error!\n\nconst misspelledKeyMap = {\n    cheese_type: "Cheese type",\n    jalapeno_qty: "Number of jalape\xc3\xb1os",\n    peppperroni: "Preppypony", // error!\n} as const satisfies Record<Keys, string>;\n
Run Code Online (Sandbox Code Playgroud)\n

Playground 代码链接

\n