645 - Diff 差集
大约 2 分钟
Diff 差集
题目
获取两个对象类型 O 和 O1 的差集,返回一个对象,包含仅存在于其中一个对象中的属性(对称差集)。
type Foo = { name: string; age: string }
type Bar = { name: string; age: string; gender: number }
type Result = Diff<Foo, Bar> // { gender: number }解答
type Diff<O, O1> = {
[K in Exclude<keyof O, keyof O1> | Exclude<keyof O1, keyof O>]:
K extends keyof O ? O[K] : K extends keyof O1 ? O1[K] : never
}更简洁的写法,利用 Omit:
type Diff<O, O1> = Omit<O & O1, keyof O & keyof O1>深入解析
理解问题
我们需要求两个对象类型的对称差集——只出现在其中一个对象中的属性。这不是简单的 Exclude,因为需要双向考虑两边的 key。
方案一:显式排除 Key
type Diff<O, O1> = {
[K in Exclude<keyof O, keyof O1> | Exclude<keyof O1, keyof O>]:
K extends keyof O ? O[K] : K extends keyof O1 ? O1[K] : never
}拆解:
Exclude<keyof O, keyof O1>— O 有但 O1 没有的 keyExclude<keyof O1, keyof O>— O1 有但 O 没有的 key- 联合 — 所有独有的 key
- 映射值 — 用条件类型取正确的值类型
方案二:交集 + Omit(优雅)
type Diff<O, O1> = Omit<O & O1, keyof O & keyof O1>更优雅:
O & O1— 交集包含两个对象的所有属性keyof O & keyof O1— 两个对象共有的 keyOmit<..., ...>— 移除共有的 key,剩下的就是差异
原理
以 Diff<Foo, Bar> 为例:
Foo = { name: string; age: string }Bar = { name: string; age: string; gender: number }
用方案二:
O & O1={ name: string; age: string; gender: number }keyof O & keyof O1="name" | "age"Omit<...>={ gender: number }✓
边界情况
// 相同对象 → 空对象
Diff<{ a: 1 }, { a: 1 }> // {}
// 完全不同 → 所有属性的并集
Diff<{ a: 1 }, { b: 2 }> // { a: 1; b: 2 }
// 有重叠但类型不同(交集语义)
Diff<{ a: string }, { a: number; b: boolean }> // { b: boolean }要点总结
- 对称差集需要双向考虑两个对象的 key
Omit<O & O1, keyof O & keyof O1>是最简洁的解法- 交集类型(
&)合并所有属性,配合Omit可以过滤我们需要的 - 这个模式适用于计算两个类型之间"有什么变化"
