Typescript 函数扩展对象如何自动保留const字面量类型无需用户手动声明
实现方案
你要的效果完全可以实现,针对不同TypeScript版本有两种成熟写法:
适配TypeScript 5.0及以上版本
使用TS 5.0新增的const类型参数特性,直接给泛型添加const修饰符,即可让TS自动按字面量类型推导传入的参数,无需用户手动加as const:
const DEFAULT_COLORS = { WHITE: '#fff' } as const // 仅在泛型前加const修饰即可 const extendColors = <const T extends Record<string, string>>(newColors: T) => { return { ...DEFAULT_COLORS, ...newColors } as const } // 调用示例,无额外语法 const colors = extendColors({ RED: '#FF0000' }) // 推导结果: // colors.WHITE 的类型是字面量 "#fff" // colors.RED 的类型是字面量 "#FF0000" // 输入colors.时会自动提示所有键,访问不存在的键会报类型错误
兼容TypeScript 5.0以下版本
如果你的组件库需要兼容更低版本的TS,可以通过拆分泛型约束的方式实现同样的效果:
const DEFAULT_COLORS = { WHITE: '#fff' } as const // 把值类型单独抽为泛型S约束为string,强制TS保留字面量 const extendColors = <T extends Record<string, S>, S extends string>(newColors: T) => { return { ...DEFAULT_COLORS, ...newColors } as const } // 调用方式完全一致 const colors = extendColors({ RED: '#FF0000' })
原理解释
你之前的写法推导失效,是因为TS默认推导可变对象参数时,会把字符串属性值拓宽为string类型,避免后续修改属性值时报错。
- 加
const泛型修饰符后,TS会默认将传入的对象视为不可变的,和手动加as const的推导效果完全一致 - 低版本的拆分泛型写法,是通过单独约束值类型为
string的子类型,强制TS不把字面量拓宽为通用string类型
内容的提问来源于stack exchange,提问作者User
相关产品推荐
相关产品推荐

