type-challenges 极端难度 Subtract:用 BuildTuple 实现类型级减法
示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载导读本篇文章围绕 type-challenges 仓库中编号 07561 的极端extreme难度题目Subtract展开讲解如何仅靠 TypeScript 类型系统、借助 用元组长度映射数字BuildTuple这一经典手段实现类型层面的整数减法并正确处理被减数小于减数时返回never的边界规则。读完本文你将掌握基于元组tuple长度做类型级算术的核心套路、读懂该题目配套模板与测试用例的约束并理解这类简单版实现为什么在数字变大时会触碰 TypeScript 递归实例化深度限制。一、题目概览一道专注简单减法的 extreme 题目Subtract 是 type-challenges 中的一道extreme极端难度题目其元数据见 info.yml标注难度extreme标签tuple元组作者LoGitHub: LoTwT题目出自 README.md核心要求只有一句话Implement the type Subtraction that is-in Javascript by using BuildTuple.即在类型层面实现 JavaScript 的减法语义-运算符且解题路线被明确指定为BuildTuple——先构造元组再通过元组长度完成数值运算。题目同时强调了两点约束If the minuend is less than the subtrahend, it should benever.当被减数小于减数即结果为负数时返回never而非负数Its a simple version.题目自称为简单版暗示该实现并不追求覆盖任意大整数这在配套测试用例中也有体现详见下文第四节。二、需求规格拆解输入、输出与边界题目给出的示例非常简洁Subtract2, 1 // expect to be 1 Subtract1, 2 // expect to be never结合模板与测试可以将行为规格完整归纳为一张表表达式结果含义SubtractM, S且 M SM - S正常减法SubtractM, S且 M S0相等时结果为 0SubtractM, S且 M Snever结果为负直接否决其中两个类型参数的命名在模板中已有注释见 template.ts// M minuend, S subtrahend type SubtractM extends number, S extends number anyM即minuend被减数S即subtrahend减数两个参数均被约束为number模板默认实现为any等待解题者替换。之所以要求小于时返回never是因为类型系统没有负数这一原生表示用元组长度无法直接表达负数结果因此用never显式拒绝该输入组合避免产生错误推断。三、测试驱动从 test-cases.ts 读懂验收标准配套测试用例位于 test-cases.ts全文如下import type { Equal, Expect } from type-challenges/utils type cases [ ExpectEqualSubtract1, 1, 0, ExpectEqualSubtract2, 1, 1, ExpectEqualSubtract1, 2, never, // ts-expect-error ExpectEqualSubtract1000, 999, 1, ]逐行解读验收标准Subtract1, 1必须精确等于0相等输入的处理是必测项说明实现不能只覆盖大减小Subtract2, 1必须精确等于1最基础的正常减法Subtract1, 2必须精确等于never验证被减数小于减数时返回never的规则ts-expect-error标注的Subtract1000, 999这是简单版最重要的证据。ts-expect-error的含义是下一行预期会产生类型错误——由于1000规模的元组递归构造会触碰 TypeScript 的实例化深度限制这行求值会报错因此被测试作者用该指令豁免避免Expect断言误伤整个用例集。测试中使用的Equal/Expect工具类型来自仓库的 utils/index.d.tsexport type ExpectT extends true T export type EqualX, Y (T() T extends X ? 1 : 2) extends (T() T extends Y ? 1 : 2) ? true : falseExpect要求传入的必须是字面量trueEqual采用函数签名比较的经典技巧能够区分1与number这类宽窄类型从而保证减法结果必须是精确的字面量类型而非number。四、核心原理用 BuildTuple 把数字翻译成元组长度题目指定使用 BuildTuple 解法。其核心思想是类型系统的两个已知事实元组的length属性是字面量数字类型例如[unknown, unknown][length]精确等于2通过递归拼接元组可以把任意数字N映射为长度恰为N的元组从而让类型系统数数。仓库中同作者同为 LoTwT的另一道 medium 题目 Construct Tuple07544 正是这一能力的直接练习题其要求为type result ConstructTuple2 // expect to be [unknown, unknown]Subtract 与 Construct Tuple 一脉相承减法可以转换为从长度为 M 的元组中移除 S 个元素剩下元组的长度即为M - S。BuildTuple 的递归构造一个标准的 BuildTuple 实现如下供理解参考非仓库模板内容type BuildTupleL extends number, T extends unknown[] [] T[length] extends L ? T : BuildTupleL, [...T, unknown]执行过程可以这样理解从空元组[]开始每次递归追加一个unknown元素即[...T, unknown]当T[length]与目标L相等时终止递归并返回T。例如BuildTuple2会依次经历[]→[unknown]→[unknown, unknown]最终得到长度为2的元组。用模式匹配做减法有了 BuildTuple减法可以通过元组解构variadic tuple types完成先分别构造BuildTupleM与BuildTupleS再用[...BuildTupleS, ...infer R]去匹配长元组剩余部分R的长度就是差值type BuildTupleL extends number, T extends unknown[] [] T[length] extends L ? T : BuildTupleL, [...T, unknown] type SubtractM extends number, S extends number M extends S ? 0 : BuildTupleM extends [...BuildTupleS, ...infer R] ? R[length] : never逻辑分支说明M extends S ? 0先处理相等情形Subtract1, 1直接命中0避免走元组构造BuildTupleM extends [...BuildTupleS, ...infer R]尝试从长元组前段剥掉 S 个元素若匹配成功说明M S剩余R[length]即为差值如Subtract2, 1→[unknown]的length为1若匹配失败M S说明减数元组比被减数元组还长永远无法匹配落入never分支如Subtract1, 2→never。五、简单版的边界递归深度限制的证据题目 README 强调 Its a simple version这一声明在测试用例中得到印证ExpectEqualSubtract1000, 999, 1被ts-expect-error包裹。从源码结构可以推断BuildTuple 采用逐元素递归构造Subtract1000, 999需要先递归生成长度 1000 的元组而 TypeScript 对类型实例化深度有硬性限制。当递归层级超过该限制时编译器会直接报 Type instantiation is excessively deep and possibly infinite 一类的错误Equal断言自然无法成立。测试作者因此用ts-expect-error将其显式豁免——既保留了大数场景下求值会报错这一事实的可见性又不会让整个用例集失败。这带来的实际约束是本实现适合M、S在几十以内的小整数场景若要支持1000及以上规模的数字需要切换到按位/字符串逐位计算等更复杂的方案例如仓库中 Sum00476、Integers Comparator00274 等 extreme 题目所采用的 template-literal 逐位进位策略。六、如何本地验证你的实现type-challenges 的题目采用类型检查即测试的模式无需运行 JavaScript将你的实现写入 template.ts 中的Subtract类型替换默认的any使用 TypeScript 编译器对 test-cases.ts 做类型检查如tsc --noEmit若所有ExpectEqual...均成立说明实现通过验收若某个Equal不成立ExpectT extends true会给出类型错误提示。测试文件依赖type-challenges/utils提供的Equal/Expect定义见 utils/index.d.ts这也是 type-challenges 全部题目共用的验收工具集。七、延伸阅读仓库中的元组与数字题目家族Subtract 并非孤立存在围绕用元组/字符串做类型级算术仓库中还有一系列可对照学习的题目题目难度技术要点Construct Tuple07544medium用元组长度映射数字Subtract 的 BuildTuple 前置技能MinusOne02257medium数字减一同样依赖元组长度递减Sum00476extreme支持大数与 bigint 的加法采用逐位计算规避递归深度限制Integers Comparator00274extreme支持负数与零的整数比较器对比可见以元组长度为算盘的简单方案Subtract、MinusOne实现直观、易于理解但受递归深度限制而以字符串逐位运算的方案Sum、Integers Comparator复杂度更高却能突破数字规模的上限。理解 Subtract正是踏入 type-challenges 类型级算术世界的第一步。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐type-challenges 极端难度题解用 TypeScript 类型系统实现 JSON Parser06228type challenges 极端难度题解用 TypeScript 类型系统实现 JSON Parser06228 type challenges 仓库示例工程两数之和Two Sum类型级实现深度拆解 type-challenges 困难题 08804两数之和Two Sum类型级实现深度拆解 type challenges 困难题 08804 本文围绕 questions/08804 hard two示例工程type-challenges 实战在类型系统中实现大整数加法 Sum\A, B\extreme 难度type challenges 实战在类型系统中实现大整数加法 Sum\A, B\ extreme 难度 本文围绕 type challenges 第示例工程上一篇Call Summary: [Company] — [Date]下一篇A2UI v0.8 自定义 Catalog 协商机制详解从一次性能力声明到按消息、按 Surface 的动态目录选择创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →