ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

type-challenges 中等题解:OmitByType —— 按属性类型(而非键名)精准剔除对象字段

2026/10/2 7:54:54 拓冰建站 浏览量
type-challenges 中等题解:OmitByType —— 按属性类型(而非键名)精准剔除对象字段 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载导读OmitByType是 type-challenges 题库中的一道中等难度medium对象类型体操题编号 2852收录于仓库 questions/02852-medium-omitbytype/。它的核心诉求与内置工具类型OmitT, K截然不同后者按键名集合剔除属性而OmitByType要求按值类型剔除属性——凡值类型可赋值给U的键全部过滤掉其余键原样保留。读完本文你将掌握键重映射key remapping 条件类型这一对象过滤套路能够独立写出通过全部测试用例的题解并理解它与姊妹题PickByType之间的镜像关系。一、题目原文与核心目标题面原文摘自 README.md非常精简FromT, pick a set of properties whose type are not assignable toU.即从对象类型T中挑出值类型不可赋值给U的那些属性组成新的对象类型。题面给出的示例type OmitBoolean OmitByType{ name: string count: number isReadonly: boolean isEnable: boolean }, boolean // { name: string; count: number }示例中isReadonly与isEnable的值类型是boolean可赋值给参数U boolean因此被剔除name: string与count: number不可赋值给boolean得以保留。题目的难度、标签与元信息记录在 info.yml 中difficulty: medium title: OmitByType tags: object author: github: jiangshanmeta name: jiangshan related: 2595可以看到它属于object对象标签系列作者是 jiangshan并且官方将其与 2595 号题PickByType标记为关联题目related。这与本仓库的目录组织一致每个题目一个独立目录包含README.md、template.ts待补全的模板、test-cases.ts官方测试用例与info.yml元信息题库总入口见根目录 README.md。二、入手前的关键区分Omit vs OmitByType在动手前必须先厘清它与内置工具类型OmitT, K的本质差异OmitT, K的第二个参数是键名字面量类型的联合剔除依据是键名在不在 K 里。本仓库对应的手写练习见 questions/00003-medium-omit/。OmitByTypeT, U的第二个参数是值类型剔除依据是T[K]是否可赋值给U。它不关心键叫什么名字只关心值的类型形态。这种差异也决定了实现思路内置Omit只需一次Excludekeyof T, K拿到保留键集合再交给Pick而OmitByType必须先按值类型筛选键——这正是本题的考点所在。三、模板文件与官方测试用例题目起点是 template.ts内容仅为占位实现type OmitByTypeT, U any我们后续的解答就是要替换掉这个any使其通过 test-cases.ts 中的全部断言。官方测试用例原文如下import type { Equal, Expect } from type-challenges/utils interface Model { name: string count: number isReadonly: boolean isEnable: boolean } type cases [ ExpectEqualOmitByTypeModel, boolean, { name: string, count: number }, ExpectEqualOmitByTypeModel, string, { count: number, isReadonly: boolean, isEnable: boolean }, ExpectEqualOmitByTypeModel, number, { name: string, isReadonly: boolean, isEnable: boolean }, ]三个用例分别以boolean、string、number作为过滤类型U覆盖了多个键被剔除单个键被剔除等场景。其中Equal与Expect来自工作区依赖包type-challenges/utils其定义位于 utils/index.d.tsExpectT extends true T用于强制类型恒等于true而Equal通过一对函数签名的条件类型比较实现严格的类型等价判定因此解答必须做到结构逐字一致例如键的顺序、可选性、readonly 修饰符不能只满足可赋值这种宽松关系。四、题解一先筛键、再 Pick经典 Exclude 思路最直观的思路分两步先找出值类型可赋值给U的键并剔除得到保留键的联合再用内置PickT, K从原对象中取出这些键。第一步需要用到条件类型 映射类型的键查询技巧。对keyof T中的每个键K判断T[K] extends Utype KeysNotAssignableToT, U { [K in keyof T]: T[K] extends U ? never : K }[keyof T]这段代码的含义是把T逐键映射成一个新对象值为never或键名K再通过索引访问[keyof T]把所有值取并集。由于never在联合类型中会被自动吸收最终结果就只剩下不可赋值给U的键名的联合。拿到保留键后交给内置Pick即可type OmitByTypeT, U PickT, KeysNotAssignableToT, U以U boolean为例isReadonly、isEnable两个键被映射为neverKeysNotAssignableTo得到name | countPickT, name | count便输出{ name: string; count: number }与题面示例及第一个测试用例完全吻合。五、题解二键重映射key remapping一步到位TypeScript 4.1 引入的键重映射as子句允许在映射类型中改写键名把键映射为never即可从结果类型中删除该键。基于此可以直接在一个映射类型内完成筛选无需先算键联合type OmitByTypeT, U { [K in keyof T as T[K] extends U ? never : K]: T[K] }对于每个键K若T[K] extends U成立则把键重映射为never键被删除否则保留键名K并携带原值类型T[K]。这套写法更紧凑也是社区中最常见的解答。从语法机制看它与题解一在语义上等价——都是保留值类型不可赋值给U的键只是把先算键联合、再 Pick的两步压缩进了一次映射。对照template.ts中type OmitByTypeT, U any的占位将any替换为上述任一实现即可让测试用例通过。六、深入理解extends判定与字面量类型陷阱理解不可赋值not assignable的判定边界是本题的关键。T[K] extends U走的是 TypeScript 的结构可赋值性规则宽类型匹配boolean类型属性会被U boolean命中如示例中的两个布尔字段字面量类型也属于可赋值若某属性的值是字面量类型true由于true extends boolean成立它同样会被U boolean剔除——这正是题面用 assignable 而非 equal 措辞的原因也是与按精确类型匹配类题目如按Equal严格比较的题的关键区别联合类型按整体判定string | number这类联合是否命中U取决于联合整体能否赋值给U需要每个成员都可赋值而不是按成员逐个拆分。从 test-cases.ts 的用例可以看出官方测试只覆盖了三种原始类型作为U并未覆盖字面量或联合类型边界在自行验证扩展用例时可以把上述边界作为补充自测点例如type Case OmitByType{ a: true, b: boolean, c: string }, boolean // 结果应为 { c: string }因为 true 与 boolean 都可赋值给 boolean七、姊妹题对比OmitByType 与 PickByType本题的关联题 questions/02595-medium-pickbytype/ 是PickByType——保留可赋值给U的属性恰好是本题的反向操作FromT, pick a set of properties whose type are assignable toU.其示例与本题共用同一个Model形状只是结果互补type OnlyBoolean PickByType{ name: string count: number isReadonly: boolean isEnable: boolean }, boolean // { isReadonly: boolean; isEnable: boolean; }对比两者的 test-cases.ts 与本题 test-cases.ts 可以发现对同一ModelPickByTypeModel, boolean得到{ isReadonly: boolean; isEnable: boolean }而OmitByTypeModel, boolean得到{ name: string; count: number }两者键集合互为补集。实现上只需要把条件分支对调// PickByType可赋值则保留键 type PickByTypeT, U { [K in keyof T as T[K] extends U ? K : never]: T[K] } // OmitByType可赋值则删除键 type OmitByTypeT, U { [K in keyof T as T[K] extends U ? never : K]: T[K] }把这两道题放在一起练习能一举掌握按类型过滤键的正反两套写法。八、如何在本仓库本地验证题解本仓库采用 pnpm workspace 管理见根目录 package.json 中的pnpm8.12.1与type-challenges/utils: workspace:*测试依赖包源码位于 utils/。本地验证步骤克隆仓库后在根目录执行pnpm install需 Node 环境与 pnpm编辑 template.ts把type OmitByTypeT, U any替换为上文任一实现用 TypeScript 编译器检查测试文件例如npx tsc --noEmit questions/02852-medium-omitbytype/test-cases.ts——若类型定义正确ExpectEqual...全部满足约束编译无错误即通过。仓库根目录 tsconfig.json 与 tsconfig.base.json 已配置好编译环境也可以直接在题目的线上 playground 地址README 头部徽章链接粘贴解答运行。九、小结OmitByType的核心价值在于把Omit的维度从键名扩展到值类型其标准解法依赖两个 TypeScript 特性条件类型T[K] extends U完成可赋值性判定映射类型的键重映射as ... never完成键的剔除。两种实现先Exclude式筛键再Pick、或一步键重映射在语义上等价读者可按习惯选用。若再与 PickByType 成对练习即可完整掌握对象类型按值类型过滤的整套思路为后续更复杂的对象型挑战如按嵌套结构过滤、按修饰符过滤等打下基础。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐Element UIVue 2.0Pagination 分页组件完全指南布局、事件与源码实现剖析Element UIVue 2.0Pagination 分页组件完全指南布局、事件与源码实现剖析 当单页需要展示的数据量过大时使用分页Paginati示例工程ant-design-vue Image 图片组件完全指南从基础展示到可控预览的实现原理与实战ant design vue Image 图片组件完全指南从基础展示到可控预览的实现原理与实战 可预览的图片组件是 ant design vue 数据展示体系示例工程CairoSVG错误处理与调试解决常见SVG转换问题的完整指南CairoSVG错误处理与调试解决常见SVG转换问题的完整指南 CairoSVG是一款强大的SVG转换工具能够将矢量图像精准转换为多种格式。然而在实际使用过图形学开发工具上一篇CANN/PTO-ISATGEMV矩阵向量乘指令下一篇打造你的个人AI知识管家qmd本地搜索引擎终极实践指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考