如何在TypeScript中实现对象差异提取并精确推导返回类型
实现精确类型推导的对象差异字段提取函数
问题描述
需要写一个函数,提取object2里和object1值不一样的字段,同时让TypeScript能精确推导返回类型(不能只是宽泛的Partial<T>)。目前的实现代码如下:
const diff = <T extends {}>(object1: T, object2: T) => { const diffValues = {} for (const key in object1) { if (object1[key] !== object2[key]) { diffValues[key] = object2[key] } } return diffValues; }
期望的类型推导效果:
const res = diff({ a: 1 }, { a: 2 }) // 返回类型 { a: number } const res = diff({ a: 1, b: 'value' }, { a: 1, b: 'value2' }) // 返回类型 { b: string }
试过lodash的omit工具函数但没成功,想知道怎么让TypeScript更精准地推导返回类型。
解决方案
要做到精确类型推导,得用TypeScript的条件类型和映射类型来过滤值不同的字段,同时在函数里做类型断言保证类型安全。
1. 定义差异类型
先定义一个Diff<T, U>类型,用来提取T和U中值类型不同的字段:
type Diff<T, U> = { [K in keyof T as T[K] extends U[K] ? never : K]: U[K] } & {}
这个类型会遍历T的所有键,当T[K]和U[K]类型不一样时保留该键,否则排除。最后加& {}是为了让类型在编辑器里展示得更清晰。
2. 实现带精确类型的diff函数
修改原函数,用泛型约束和类型断言让返回值对应Diff<T, U>:
const diff = <T extends object, U extends T>(object1: T, object2: U): Diff<T, U> => { const diffValues = {} as Diff<T, U>; for (const key in object1) { if (object1[key] !== object2[key]) { diffValues[key as keyof Diff<T, U>] = object2[key] as Diff<T, U>[keyof Diff<T, U>]; } } return diffValues; }
3. 验证效果
测试几个示例:
// 返回类型 { a: number } const res1 = diff({ a: 1 }, { a: 2 }) // 返回类型 { b: string } const res2 = diff({ a: 1, b: 'value' }, { a: 1, b: 'value2' }) // 返回类型 {}(所有字段值都相同) const res3 = diff({ a: 1, b: 'test' }, { a: 1, b: 'test' })
关键点说明
- 泛型
U extends T确保object2是object1的子类型,避免出现object2有额外字段的情况 Diff<T, U>通过条件类型过滤出类型不同的字段,再结合运行时的!==校验,保证返回的是实际值不同的字段- 类型断言
as Diff<T, U>让TypeScript认可返回值的精确类型,不会再推断成宽泛的{}
内容的提问来源于stack exchange,提问作者Bruce Lee
相关产品推荐
相关产品推荐

