ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

type-challenges 中等题解:用 TypeScript 类型系统实现 Diff 对象差集

type-challenges 中等题解:用 TypeScript 类型系统实现 Diff 对象差集 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载导读本文深入解析 type-challenges 题库第 00645 号中等难度挑战Diff编写一个类型工具DiffO, O1从两个对象类型中取出只存在于其中一方的差值属性返回一个新的对象类型。该挑战归属于#object标签见 info.yml是理解keyof、联合类型分布、Pick/Omit内置工具类型之间协作关系的经典练习。读完本文你将掌握对象类型对称差集的两种核心实现思路并能熟练利用keyof (O | O1)与keyof (O O1)的键集差异来构造任意差集类型。一、题目要求与定位在仓库 questions/00645-medium-diff/ 目录中题目以多语言 README 呈现。日文版 README.ja.md 的题面为OとO1の差を表すObjectを返却します。即返回一个表示O与O1之差的Object。中文版 README.zh-CN.md 给出更直观的表述获取两个接口类型中的差值属性并附带如下示例type Foo { a: string; b: number; } type Bar { a: string; c: boolean } type Result1 DiffFoo, Bar // { b: number, c: boolean } type Result2 DiffBar, Foo // { b: number, c: boolean }关键点在于Diff是对称的。无论把Foo还是Bar放在前面得到的结果都是{ b: number, c: boolean }——即两个对象各自独有属性的并集而共同属性a被剔除。这与Omit剔除指定键或Pick挑选指定键这种单向操作有本质区别。题目的元数据存放在 info.yml 中明确了难度为medium标签为object作者为 ZYSzys。起始模板 template.ts 只有一行占位实现type DiffO, O1 any接下来要做的就是把any替换成真正的类型运算。二、理解测试用例行为规范即验收标准仓库的每一个挑战都配有 test-cases.ts这是判断实现是否正确的唯一依据。Diff 的测试用例如下import type { Equal, Expect } from type-challenges/utils type Foo { name: string age: string } type Bar { name: string age: string gender: number } type Coo { name: string gender: number } type cases [ ExpectEqualDiffFoo, Bar, { gender: number }, ExpectEqualDiffBar, Foo, { gender: number }, ExpectEqualDiffFoo, Coo, { age: string, gender: number }, ExpectEqualDiffCoo, Foo, { age: string, gender: number }, ]由这 4 个用例可以归纳出 Diff 的完整行为规范DiffFoo, BarFoo与Bar的共有键是name与ageBar独有gender结果为{ gender: number }DiffBar, Foo交换参数顺序结果完全相同印证了对称性DiffFoo, CooFoo独有ageCoo独有gender结果把两边独有属性合并为{ age: string, gender: number }DiffCoo, Foo再次验证对称性。注意第 3、4 个用例差集并非第二个减去第一个而是把双方各自独有的键全部收集起来。用集合论的语言说就是求两个键集合的对称差Symmetric Difference。测试中使用的Equal与Expect来自仓库的 utils/index.d.ts其中Equal通过函数签名的条件类型推断来实现对两类型完全相等的严格判定而ExpectT extends true会在T不为true时直接编译报错。也就是说你的实现必须产出字面上完全一致的对象类型包括属性名与值类型多一个键、少一个键、值类型不符都会导致编译失败。三、核心原理用键集运算表达对称差在动手写实现前先掌握一个关键的类型运算事实——对象类型的键集在联合与交叉下的分布行为。给定两个对象类型O与O1keyof (O O1)会展开为keyof O | keyof O1即两个键集合的并集keyof (O | O1)会展开为keyof O keyof O1即两个键集合的交集。为什么因为交叉类型O O1同时拥有两个对象的所有属性其键自然是并集而联合类型O | O1只有在两个分支都拥有的属性才能被安全访问其可访问键是交集。于是对称差 并集 − 交集可以直接写成type SymmetricDifferenceO, O1 Excludekeyof (O O1), keyof (O | O1)这里的ExcludeT, U是 TypeScript 内置工具类型语义为从联合T中剔除U中的成员。四、解法一Pick 提取差值键推荐有了对称差键集合后再配合Pick从某个同时拥有全部键的对象中提取即可。由于O O1同时包含两边的所有属性最自然的实现是type DiffO, O1 PickO O1, Excludekeyof (O O1), keyof (O | O1)执行流程拆解如下keyof (O O1)得到并集键例如对Foo、Bar得到name | age | genderkeyof (O | O1)得到交集键即name | ageExclude...算出对称差genderPickO O1, gender从交叉类型中取出gender属性得到{ gender: number }。等价地也可以把并集减交集替换为Omit语义——从O O1中剔除公共键type DiffO, O1 OmitO O1, keyof (O | O1)这两种写法在常规对象类型上结果一致Omit版本更简短。它们的共同前提是O与O1都是普通对象类型属性值类型保持一致在交叉类型O O1中若同名键值类型不同会退化为二者的交叉类型例如string number这一点需要留意。验证一下对称性由于O O1与O1 O等价keyof (O | O1)与keyof (O1 | O)也等价因此DiffFoo, Bar与DiffBar, Foo必然得到同一结果与 test-cases.ts 中的用例完全吻合。五、解法二先剔除公共键再合并拆分思路另一种直观思路是把两个对象各自独有的部分分别取出再合并。对O而言独有键就是Excludekeyof O, keyof O1对O1同理。于是type DiffO, O1 PickO, Excludekeyof O, keyof O1 PickO1, Excludekeyof O1, keyof O不过直接使用得到的是交叉类型为了让最终结果呈现为扁平的对象字面量类型可以借助映射类型展开type DiffO, O1 { [K in | Excludekeyof O, keyof O1 | Excludekeyof O1, keyof O]: (O O1)[K] }这里(O O1)[K]保证取值时无论K来自哪一边都能正确索引。这种先拆再合的写法更贴近集合论的直觉但代码量略大相比之下解法一直接利用keyof (O | O1)与keyof (O O1)的关系一行即可完成。无论采用哪种写法最终都需要通过仓库的测试验证。本仓库在根目录 package.json 中以workspace:*依赖 utils/package.json 中发布的type-challenges/utils读者可结合 TypeScript 的tsc或在线 playground 对模板 template.ts 与测试 test-cases.ts 进行本地校验。六、总结与延伸Diff挑战的完整实现只需掌握两个要点键集运算keyof (O O1)给出键并集keyof (O | O1)给出键交集二者之差即为对称差组合内置工具Exclude负责剔除Pick/Omit负责提取或剔除属性映射类型负责扁平化。这与题库中其他#object标签的中等题互为呼应例如 00003-medium-omit 练习Omit与条件类型00004-easy-pick 练习Pick与映射类型。在 00003-medium-omit/template.ts 中你可以看到MyOmitT, K同样以keyof、Exclude与映射类型为核心其测试用例位于 test-cases.ts可见这些对象工具类型在题库中被反复锤炼。掌握Diff之后你便能在实际项目中轻松构造两套配置、两份 API 响应之间的差异类型例如比对前后两次接口返回、实现配置项的增量合并等场景。这一模式是 TypeScript 类型编程中集合思维的典型代表把一切对象操作先抽象为键集合上的运算再用内置工具类型组合落地。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐type-challenges 第 16 题 Pop用 TypeScript 类型系统实现数组「出栈」type challenges 第 16 题 Pop用 TypeScript 类型系统实现数组「出栈」 本题是 type challenges 中一道难度为「示例工程InvenTree 开源库存管理系统零件分类与库存流水 15 分钟跑通InvenTree 开源库存管理系统零件分类与库存流水 15 分钟跑通 InvenTree 是一套开源的库存管理系统核心是零件库 库存台账两件事你后端前端企业应用ERP如何掌握Type Challenges中的Diff类型完整指南与实战案例如何掌握Type Challenges中的Diff类型完整指南与实战案例 Type Challenges是一个专注于提升TypeScript和泛型编程能力的学示例工程上一篇LinkSwift九大网盘直链解析工具终极指南彻底告别下载限速下一篇老旧设备电视直播难题的终极解决方案MyTV-Android深度评测创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表