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

TypeScript提取对象属性值为类型时得到string而非字面量联合类型

问题原因

你写的类型提取逻辑本身没有问题,问题出在tokenStatus的默认类型推导规则上:使用普通const声明对象时,TypeScript会默认对内部的字符串、数字等原始值做类型拓宽,也就是把'ENABLED'这类字面量值推导为宽泛的string类型,最终提取出来的自然就是string而不是精确的字面量联合类型。

正确实现方案

方案1:使用as const常量断言(最简便,推荐优先使用)

给tokenStatus对象整体加上as const断言,告诉TypeScript不要做类型拓宽,保留所有属性值的精确字面量类型,同时所有属性会被标记为只读:

export const tokenStatus = {
    active: {
        status: 'ENABLED',
        label: 'Active',
        type: 'success'
    },
    suspended: {
        status: 'DISABLED',
        label: 'Suspended',
        type: 'warning'
    },
    deleted: {
        status: 'DELETED',
        label: 'Deleted',
        type: 'error'
    },
} as const; // 常量断言加在对象末尾

// 保持你原来的提取写法即可得到预期类型
type ITokenStatus = typeof tokenStatus[keyof typeof tokenStatus]['status'];
// 推导结果:'ENABLED' | 'DISABLED' | 'DELETED'

如果不希望整个对象的所有属性都变成只读,也可以单独给每个status字段的值加as const断言,只是写法相对繁琐。

方案2:显式定义类型约束(适合需要校验常量结构的场景)

如果你需要在定义常量时就约束字段格式,避免后续修改时写错status等字段值,可以先定义类型再给常量标注类型:

// 先定义目标联合类型
type ITokenStatus = 'ENABLED' | 'DISABLED' | 'DELETED';
// 定义单个状态项的结构
interface StatusItem {
    status: ITokenStatus;
    label: string;
    type: 'success' | 'warning' | 'error';
}
// 给常量标注类型,约束所有属性符合结构
export const tokenStatus: Record<string, StatusItem> = {
    active: {
        status: 'ENABLED',
        label: 'Active',
        type: 'success'
    },
    suspended: {
        status: 'DISABLED',
        label: 'Suspended',
        type: 'warning'
    },
    deleted: {
        status: 'DELETED',
        label: 'Deleted',
        type: 'error'
    },
};

这种写法下如果写status时传入了不在联合类型里的值,TypeScript会直接抛出类型错误,适合对常量合法性有强校验需求的场景。


内容的提问来源于stack exchange,提问作者Preetham Sridhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:48:46