You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:15:25