TypeScript如何从对象提取实际键作为类型?解决string|number问题
解决TypeScript中无法提取对象具体键名联合类型的问题
问题的核心是你给rawResources显式标注了ItemCollection类型,这个类型带有字符串索引签名,TypeScript会优先使用显式标注的类型,忽略as const带来的字面量类型收窄,导致keyof typeof rawResources只能得到string | number。
下面提供两种可行的解决方案:
方案一:使用satisfies关键字(TypeScript 4.9+推荐)
satisfies可以确保变量符合指定类型的结构约束,但不会覆盖变量本身的字面量类型,完美保留as const带来的类型收窄效果:
export interface Item { name: string; } export type ItemCollection = {[k:string]: Item}; // 用satisfies约束结构,同时保留字面量类型和只读性 export const rawResources = { ironOre: { name: "Iron Ore", }, copperOre: { name: "Copper Ore", }, wood: { name: "Wood", }, water: { name: "Water", } } as const satisfies ItemCollection; export type RawResourceId = keyof typeof rawResources; // RawResourceId 类型为 "ironOre" | "copperOre" | "wood" | "water"
方案二:拆分变量定义(兼容低版本TypeScript)
如果你的项目还不支持satisfies,可以通过拆分变量的方式,先让TypeScript推导出自定义字面量类型,再验证其是否符合ItemCollection的结构:
export interface Item { name: string; } export type ItemCollection = {[k:string]: Item}; // 先推导字面量类型,保留as const的约束 const _rawResources = { ironOre: { name: "Iron Ore", }, copperOre: { name: "Copper Ore", }, wood: { name: "Wood", }, water: { name: "Water", } } as const; // 编译时验证是否符合ItemCollection类型 export const rawResources: ItemCollection = _rawResources; export type RawResourceId = keyof typeof _rawResources; // RawResourceId 同样得到具体的键名联合类型
为什么原写法不生效?
当你给变量显式标注ItemCollection类型时,TypeScript会将该变量的类型锁定为带有字符串索引的对象,as const只能让对象的属性变为只读,但无法改变变量的整体类型推导逻辑。因此typeof rawResources等价于ItemCollection,而keyof ItemCollection的结果就是字符串索引签名对应的string | number。
内容的提问来源于stack exchange,提问作者Marko Taht
相关产品推荐
相关产品推荐

