如何用TypeScript编写修改对象指定数值类型属性的函数?
解决TypeScript中泛型函数修改数字属性的类型约束问题
需求是实现一个double函数,接收对象和属性名,将该属性的值翻倍。JavaScript实现十分直接,但TypeScript的泛型类型检查会带来约束问题,以下是可行的解决办法:
报错原因梳理
- 第一种写法报错:
keyof T对应的属性类型不明确,TypeScript无法确认它属于可执行算术操作的类型(number/bigint等),因此阻止操作。 - 第二种写法报错:
T[K]可能是number的子类型(比如字面量类型5),直接赋值普通number类型会触发子类型不兼容的错误。
可行解决方案
方案1:类型断言快速实现
直接用类型断言告知TypeScript目标属性为number类型,绕过类型检查:
function double<T>(object: T, property: keyof T) { (object[property] as number) *= 2; }
特点:写法简洁,但如果传入非数字属性会导致运行时错误,适合能保证调用参数合法的场景。
方案2:运行时类型检查+类型断言
先通过运行时检查确认属性为数字,再用断言解决子类型兼容问题:
function double<T, K extends keyof T>(object: T, property: K): void { const value = object[property]; if (typeof value === 'number') { object[property] = value * 2 as T[K]; } }
特点:增加运行时校验,安全性更高;用as T[K]确保赋值结果符合原类型约束,解决字面量子类型的兼容问题。
方案3:严格约束对象属性类型
直接限制传入对象的目标属性必须为number类型:
function double<K extends keyof any>(object: { [P in K]: number }, property: K) { object[property] *= 2; }
也可以用Record简化写法:
function double<K extends string>(object: Record<K, number>, property: K) { object[property] *= 2; }
特点:编译期就会阻止非数字属性的传入,彻底避免运行时错误;对象包含其他非数字属性时,只要目标属性符合要求即可正常使用。
方案4:利用asserts增强类型推断(TS 3.7+)
通过asserts语法让TypeScript知晓,调用函数后目标属性的类型为number,提升后续代码的类型推断能力:
function double<T, K extends keyof T>(object: T, property: K): asserts object is T & { [P in K]: number } { (object[property] as number) *= 2; }
特点:调用函数后,TypeScript会自动将目标属性的类型推断为number,后续代码无需重复做类型检查;同样需要保证传入的属性确实是数字类型。
内容的提问来源于stack exchange,提问作者Jacob Lockard
相关产品推荐
相关产品推荐

