ARTICLE DETAIL

资讯详情

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

type-challenges 实战:不使用内置工具类型,从零实现 Parameters<T>(infer 与元组类型深度解析)

type-challenges 实战:不使用内置工具类型,从零实现 Parameters<T>(infer 与元组类型深度解析) 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载本篇技术指南围绕 type-challenges 仓库中的第 3312 号简单题「Parameters」展开核心任务是不直接使用 TypeScript 内置的ParametersT工具类型而是从零实现一个功能等价的MyParametersT。该题位于 questions/03312-easy-parameters/README.zh-CN.md通过它你可以系统掌握条件类型中的infer关键字如何提取函数参数列表以及元组类型tuple在类型工具中的核心地位。读完本文你将能够独立写出MyParametersT的完整实现理解其模板约束、测试验证方式与各类边界情况并为后续攻克ReturnType、AppendArgument等依赖infer的进阶题目打下基础。一、题面解读任务是什么原题文档的要求非常精炼实现内置的ParametersT类型而不是直接使用它。这是一个典型的「类型体操」题目——先理解内置工具类型的工作原理再用更底层的类型语法把它复刻出来。题面给出的示例const foo (arg1: string, arg2: number): void {} type FunctionParamsType MyParameterstypeof foo // [arg1: string, arg2: number]也就是说MyParameterstypeof foo应该推导出[arg1: string, arg2: number]—— 一个由函数foo的参数类型构成的元组。从 questions/03312-easy-parameters/info.yml 的元数据可以看到本题的定位字段值含义difficultyeasy难度为「简单」适合作为 infer 入门题titleParameters题目名称tagsinfer, tuple, built-in涉及条件类型推断、元组、内置工具类型三大主题三个标签恰好勾勒出解题的全部知识地图用infer做类型提取infer、提取结果是元组tuple、对标的内置工具类型built-in。二、认识内置 Parameters 它到底做了什么在动手实现之前先明确内置ParametersT的语义。它是 TypeScript 官方 Utility Types工具类型家族的一员功能是提取函数类型的参数列表并以元组形式返回。典型行为如下// 有参函数 → 参数元组 type A Parameters(arg1: string, arg2: number) void // [arg1: string, arg2: number] // 无参函数 → 空元组 type B Parameters() void // [] // 单个对象参数 → 元组中对应对象类型 type C Parameters(arg: { a: A }) void // [arg: { a: A }]几个值得注意的细节返回值与实现无关ParametersT只关心参数列表() void、() string、() Promiseboolean等不同返回类型不影响结果空参函数返回空元组[]这与直觉一致且是测试用例中专门覆盖的边界元组可以带标签从 TypeScript 4.0 起ParametersT推导出的元组会保留arg1:、arg2:这类参数名标签这正是题面示例注释里[arg1: string, arg2: number]的由来。在本仓库中内置ParametersT还被更广泛地使用。例如 utils/index.d.ts 里的测试辅助类型ExpectValidArgs就是直接基于它实现的export type ExpectValidArgsFUNC extends (...args: any[]) any, ARGS extends any[] ARGS extends ParametersFUNC ? true : false这从侧面说明ParametersT是构建更复杂类型工具的基础积木理解了它的实现原理就等于理解了大量类型工具的「心脏」。三、从模板出发读懂给定的约束条件仓库为每道题都提供了起始模板文件 questions/03312-easy-parameters/template.ts本题模板如下type MyParametersT extends (...args: any[]) any any模板已经替我们做了一件重要的事——给出了类型参数T的约束constraintT extends (...args: any[]) any这个约束意味着T必须是一个函数类型参数列表任意、返回值任意。它的作用有二编译期拦截当MyParameters被传入非函数类型如string、{ a: 1 }时直接报类型错误避免后续infer逻辑收到无法匹配的输入保证infer分支可达后续条件类型中的函数模式匹配能始终命中。而右侧的 any就是留给解题者替换的占位符——这也是整个 type-challenges 项目的通用设计题目给出约束骨架由你来填充真正的类型逻辑。四、核心解法用 infer 提取参数元组infer是 TypeScript 条件类型Conditional Types中的关键字用于在模式匹配过程中声明一个待推断的类型变量。它的语法骨架是T extends SomePattern ? (模式中 infer 到的类型) : fallback把「函数类型」看作一个可匹配的模式参数列表就是我们要从中推断的那一部分。于是MyParametersT的完整实现只需一行type MyParametersT extends (...args: any[]) any T extends (...args: infer P) any ? P : never逐段拆解这一行代码片段作用T extends (...args: any[]) any外层约束仅接受函数类型T extends (...args: infer P) any条件类型模式匹配把T与「函数形态」比对infer P在args的位置声明推断变量P将被推断为参数元组类型? P : never匹配成功返回P失败返回never当T typeof foo即(arg1: string, arg2: number) void时infer P会把P推断为[arg1: string, arg2: number]这正是题面要求的输出。这里的never分支在理论上几乎不会被触发——因为外层约束已经保证了T是函数类型内层的函数模式必然匹配成功。但条件类型语法强制要求两个分支都必须存在never是最贴近语义的兜底选择「不可能」就返回「never」。五、用测试用例验证实现type-challenges 的每道题都配有类型级测试文件 questions/03312-easy-parameters/test-cases.ts它们会在题目通过在线评测online judge时被自动执行。本题包含三组断言import type { Equal, Expect } from type-challenges/utils function foo(arg1: string, arg2: number): void {} function bar(arg1: boolean, arg2: { a: A }): void {} function baz(): void {} type cases [ ExpectEqualMyParameterstypeof foo, [string, number], ExpectEqualMyParameterstypeof bar, [boolean, { a: A }], ExpectEqualMyParameterstypeof baz, [], ]三组用例分别验证了三个能力维度多参数提取foo的[string, number]验证基础多参数场景复杂类型参数bar的[boolean, { a: A }]验证对象字面量类型也能被原样纳入元组零参数边界baz的[]验证空参函数必须返回空元组。测试断言依赖两个来自 utils/index.d.ts 的工具类型ExpectT extends true把类型断言约束为字面量trueEqualX, Y通过「函数参数位置的可赋值性比较」实现严格类型相等判断只有两个类型完全一致时才产出true。因此ExpectEqualMyParameterstypeof baz, []这种写法意味着只要MyParameterstypeof baz不是严格等于[]比如是never或any测试就会失败。这种严格的相等断言正是类型体操评测的精髓——结果必须精确到「一个类型都不差」。如果你的答案得到的是[string, number] | never之类的联合类型或者不小心返回了any都会在这里被Equal拦截下来。六、边界情况真实场景下的参数形态内置ParametersT面对真实世界中的各种函数形态时行为值得逐一确认。以下均属于 TypeScript 类型系统的标准行为我们的MyParametersT因为复刻了同一套infer逻辑表现也完全一致1. 可选参数type P MyParameters(a?: number) void // [a?: number | undefined]可选参数会保留?标记且类型会联合上undefined。2. 剩余参数rest 参数type P MyParameters(...args: number[]) void // args: number[]剩余参数在元组中以数组形式整体呈现。3. 函数重载function over(arg1: string): string function over(arg1: string, arg2: number): string function over(...args: any[]): any {} type P MyParameterstypeof over // 取最后一个重载签名实现签名的参数列表对于重载函数ParametersT提取的是实现签名的参数类型而不是某个重载声明——这是使用Parameters时最容易踩的坑实现重载函数的类型工具时尤其要留意。4. 泛型函数type P MyParametersT(x: T) T // [x: unknown]泛型参数在提取时会被泛化为unknown兜底受约束时取约束类型。这些行为共同说明ParametersT的核心价值是把「函数」这种可调用形态降维成可遍历、可索引、可映射的「元组」形态从而让后续的类型运算如AppendArgument追加参数、FlipArguments反转参数变得可能。七、姊妹题对照Parameters 与 ReturnType 的对称之美理解了ParametersT就顺带掌握了另一道高频题。仓库中的 questions/00002-medium-return-type/README.zh-CN.md 要求实现MyReturnTypeT其题面示例是const fn (v: boolean) { if (v) return 1 else return 2 } type a MyReturnTypetypeof fn // 应推导出 1 | 2对照两个实现结构几乎完全相同只是infer的位置从「参数侧」移到了「返回值侧」// Parameters推断参数元组 type MyParametersT extends (...args: any[]) any T extends (...args: infer P) any ? P : never // ReturnType推断返回值 type MyReturnTypeT extends (...args: any[]) any T extends (...args: any[]) infer R ? R : never两者共享同一个模式匹配框架把函数类型拆成(...args) R再用infer分别钉住参数区或返回值区。可以说Parameters和ReturnType是学习infer的最佳入门双胞胎前者产出元组后者可以产出联合类型如1 | 2见 questions/00002-medium-return-type/test-cases.ts 中的typeof fn用例。八、方法论沉淀infer 的通用价值最后把视角拉高一层。MyParametersT只是一行代码但它揭示了整个 type-challenges 体系中反复出现的核心模式约束先行用extends约束输入类型域缩小infer需要面对的形态空间模式拆解把复杂类型函数、数组、对象、字符串模板拆成可匹配的「模式」infer 钉住目标在模式中精确标记需要提取的片段两分支完备条件类型永远给出「命中」与「未命中」两条路径。这个模式在本仓库的无数题目中复用ReturnType提取返回值、AppendArgument在参数元组后追加一项、TupleToUnion元组转联合、以及各类字符串模板解析题如Trim、Replace底层都是同一套「约束 模式 infer」的组合拳。当你把 questions/03312-easy-parameters/template.ts 中的any替换为T extends (...args: infer P) any ? P : never并通过 test-cases.ts 的全部断言时你掌握的不仅是一道简单题而是 TypeScript 类型系统中最重要的推理引擎。更多同系列挑战可以从 README.zh-CN.md 的题目列表继续探索。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐type-challenges 实战从零实现 TypeScript 内置类型 ExcludeT, Utype challenges 实战从零实现 TypeScript 内置类型 ExcludeT, U 导读 本文以 type challenges 题库第示例工程type-challenges 第 4 题解析手写实现内置类型工具 MyPickT, Ktype challenges 第 4 题解析手写实现内置类型工具 MyPickT, K 本文是 type challenges https://link.示例工程type-challenges 手写内置工具类型 Pick\T, K\从零实现、测试用例解析与底层原理type challenges 手写内置工具类型 Pick\T, K\ 从零实现、测试用例解析与底层原理 导读 本文以 type challenges 仓库示例工程上一篇Style2Paints V4.5配置文件备份工具自动备份设置的软件下一篇安卓WorkManager取消策略终极指南如何高效管理园艺应用的定期任务 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表