TypeScript能否从动态未知数组获取精确字面量联合类型?
问题根源
问题出在Object.keys()的内置类型定义上:TypeScript 中Object.keys()的返回值固定为string[]类型,这是TS的有意设计——由于JS对象在运行时可能存在类型定义里没声明的额外属性,TS出于类型安全考虑,不会自动把返回值推导为对象键的字面量联合类型。
你给动态生成的数组加as const时,只能把string[]断言为只读的字符串数组,没法收窄到具体的字符串字面量,所以typeof IconNames[number]最终推导结果就是string。而你手写的IconSizes是直接写死的字符串字面量数组,加as const后TS能直接推导出每个元素的精确字面量类型,所以能正常得到联合类型。
修复方案
直接通过keyof拿到图标模块的导出键类型,手动给生成的数组做类型断言即可:
import * as Icons from "@icons"; // 先获取图标模块所有导出键的联合类型 type IconNameKey = keyof typeof Icons; // 对Object.keys的返回值做类型断言 const IconNames = Object.keys(Icons) as readonly IconNameKey[]; const IconSizes = ["sm", "md", "lg"] as const; // 此时icon类型就能正确推导为所有图标名的联合类型 // type IconProp = { icon: typeof IconNames[number]; size: typeof IconSizes[number] }
如果需要完全和IconSizes一致的只读元组效果,在TS5.0+版本可以配合satisfies做额外校验,避免断言写错类型:
const IconNames = [...Object.keys(Icons)] as const satisfies readonly IconNameKey[];
注意:不建议通过修改TS内置
Object.keys类型定义的方式强制推导出字面量联合,这种写法会绕过TS的安全检查,如果导入的图标模块被打包工具注入了额外属性(比如模块标识、默认导出别名等),可能会出现类型声明和运行时实际值不匹配的问题。
内容的提问来源于stack exchange,提问作者Paraform Creative
相关产品推荐
相关产品推荐

