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
相关产品推荐
相关产品推荐

