ARTICLE DETAIL

资讯详情

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

TypeScript 类型挑战 59:用 GetOptional<T> 提取对象类型中的可选属性

TypeScript 类型挑战 59:用 GetOptional<T> 提取对象类型中的可选属性 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载本篇技术指南围绕 type-challenges 仓库第 59 号挑战「Get Optional」展开完整讲解高级工具类型GetOptionalT的题目要求、测试用例语义、实现思路与最终解法并对照第 57 号挑战GetRequiredT进行差分分析。读完本文后你将掌握如何用映射类型Mapped Types与as子句在类型层面筛选键集合并理解可选属性在类型系统中的精确判定方式包括undefined值属性的边界陷阱能够独立实现这一类按键属性筛选的工具类型。题目概览难度、标签与作者本挑战位于 questions/00059-hard-get-optional/由作者 Zheeeng 提出属于hard困难级别。从其元信息文件 info.yml 可以看到difficulty: hard困难难度title: Get Optionaltags: utils, infer标签为工具类型与类型推断related: 57关联第 57 号挑战 Get Required。题目在日文版 README.ja.md 中描述为实现一个高级实用工具类型GetOptionalT该类型仅保留所有**可选optional**字段。配套的简体中文版 README.zh-CN.md 给出了同样的描述实现高级工具类型GetOptionalT该类型保留所有可选属性。目标与示例题目给出的最小示例非常直观type I GetOptional{ foo: number, bar?: string } // expected to be { bar?: string }即输入一个对象类型foo是必选属性、bar是带?的可选属性输出应只保留bar?: string把必选属性foo剔除掉。在动手之前我们先理解可选在类型层面的含义bar?: string表示该属性可以缺省其实际取值类型在读取时是string | undefined。因此GetOptionalT本质上要做的是——遍历keyof T判断每个键是否为可选键然后只保留那些可选键对应的属性。测试用例深度解读为什么要设计第二个用例题目自带的测试文件 test-cases.ts 定义了判定标准import type { Equal, Expect } from type-challenges/utils type cases [ ExpectEqualGetOptional{ foo: number, bar?: string }, { bar?: string }, ExpectEqualGetOptional{ foo: undefined, bar?: undefined }, { bar?: undefined }, ]这里有两个值得注意的细节判定工具Equal与Expect来自仓库独立的工具包type-challenges/utils其实现位于 utils/index.d.ts。其中EqualX, Y使用函数参数逆变位置的类型等价性判定(T() T extends X ? 1 : 2) extends (T() T extends Y ? 1 : 2)比extends单向可赋值判定更严格能精确区分any、unknown等特殊类型。第二个用例是陷阱用例{ foo: undefined, bar?: undefined }中foo是必选属性且值类型为undefinedbar是可选属性且值类型为undefined。期望结果是{ bar?: undefined }。这个用例专门用来拦截只看值类型的朴素解法——因为foo与bar的值类型都是undefined仅凭值类型根本无法区分谁是必选谁是可选。这逼迫解法必须在**键的可选性modifier**层面做文章。思路分析从问题分解到键集合筛选GetOptionalT的实现可以分解为三个步骤遍历所有键使用映射类型{ [K in keyof T]: ... }判断每个键是否为可选键这是全题的核心难点需要一种能在类型层面回答K是否可选的判定手段筛选在as子句中把非可选键映射为never实现键集合的过滤。as子句是 TS 4.1 提供的能力形如{ [K in keyof T as NewK]: T[K] }其中NewK可以是never——一旦某个键被映射为never该属性就不会出现在结果类型中。那么如何判断一个键是否可选呢一个自然的思路是利用内置的RequiredTRequiredT会把 T 的所有属性都变成必选去掉?。于是对每个键K若K原本必选则T[K]与RequiredT[K]完全一致若K原本可选则T[K]是X | undefined而RequiredT[K]是X。但这会踩中前面提到的陷阱当可选属性的值类型本身就是undefined时如bar?: undefinedT[bar]与RequiredT[bar]都是undefined二者无法区分。关键难点{} extends PickT, K判定法更稳健的方案是利用空对象是否能赋值给该键的对象类型这一特性。构造辅助类型type IsOptionalKeyT, K extends keyof T {} extends PickT, K ? true : false原理如下如果K是可选属性那么PickT, K形如{ bar?: string }所有属性都可缺省因此空对象{}可以赋值给它满足结构兼容{} extends PickT, K成立如果K是必选属性PickT, K形如{ foo: number }或{ foo: undefined }空对象{}缺少该必选属性无法赋值判定为false。关键在于这个判定发生在属性是否存在的层面而不是值类型是什么的层面所以无论可选属性的值类型是string还是undefined判定结果都正确。这正是它能通过{ foo: undefined, bar?: undefined }用例的原因。参考解法完整实现基于上述思路一个简洁且能通过全部测试用例的实现如下type GetOptionalT { [K in keyof T as {} extends PickT, K ? K : never]: T[K] }逐段拆解keyof T取出 T 的所有键PickT, K提取单个键K对应的属性得到{ K: T[K] }或{ K?: T[K] }{} extends PickT, K ? K : never若K为可选键则保留为K否则映射为never将其丢弃: T[K]保留原属性值类型包括其可选修饰符语义下的联合类型。验证两个测试用例GetOptional{ foo: number, bar?: string }{} extends { foo: number }为 false → 丢弃foo{} extends { bar?: string }为 true → 保留bar结果为{ bar?: string }✓GetOptional{ foo: undefined, bar?: undefined }{} extends { foo: undefined }为 false → 丢弃foo{} extends { bar?: undefined }为 true → 保留bar结果为{ bar?: undefined }✓。与之配套第 57 号挑战GetRequiredT只需把条件取反实现几乎是对偶的type GetRequiredT { [K in keyof T as {} extends PickT, K ? never : K]: T[K] }其测试用例 questions/00057-hard-get-required/test-cases.ts 同样包含ExpectEqualGetRequired{ foo: undefined, bar?: undefined }, { foo: undefined }——两个挑战互为镜像验证了同一套判定逻辑在保留必选与保留可选两个方向上都成立。在仓库中运行与验证要亲身体验这道题可以按如下方式操作仓库根目录为GitHub_Trending/ty/type-challenges查看题目描述questions/00059-hard-get-optional/README.ja.md或 README.zh-CN.md、README.md打开模板文件 template.ts其中初始实现为type GetOptionalT any需替换为上文解法运行测试用例 test-cases.ts确保两个ExpectEqual...全部通过。仓库根 package.json 采用 pnpm workspace 管理type-challenges/utils为 workspace 依赖见 utils/package.jsonTypeScript 版本为 ^5.3.3tsconfig基于 tsconfig.base.jsonstrict: true可在编辑器或tsc --noEmit下获得即时的类型检查反馈。延伸思考判定方式的可替换性{} extends PickT, K之外社区也常见T[K] extends RequiredT[K]的写法后者对值类型为undefined的可选属性会失效这正是本题测试用例刻意设计的区分点与keyof家族的组合GetOptional/GetRequired与仓库中其他键筛选类挑战如 00005-extreme-readonly-keys 判断 readonly 键共享同一套映射类型 as never 条件判定的方法论掌握后可以快速迁移到任意属性修饰符筛选场景实际工程价值在编写表单校验、配置合并、可选配置默认值填充等场景中区分对象类型里哪些键可选、哪些键必选是常见的类型层需求GetOptional这类工具可以直接支撑Partial/Required之外更精细的类型变换。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐CANN/GE模型执行API文档aclmdlExecutea nameZH CN_TOPIC_0000001264921926 /a 产品支持情况a namesection15人工智能深度学习模型编译模型优化编译器AscendHydra 命令行参数完全指南理解 Hydra 专属 Flags 与配置覆盖机制Hydra 命令行参数完全指南理解 Hydra 专属 Flags 与配置覆盖机制 本篇技术指南以 Hydra 1.0 官方文档《Hydras command示例工程CloudNativePG 资源管理深度指南从 QoS 调度到 VPA/HPA 自动伸缩实践CloudNativePG 资源管理深度指南从 QoS 调度到 VPA/HPA 自动伸缩实践 导读 本文围绕 CloudNativePGCNPG官方文档中示例工程上一篇tf_efficientnetv2_s.in21k_ft_in1k部署实战从开发到生产环境的完整指南下一篇Agent-Native模板解析AI辅助幻灯片设计的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表