ARTICLE DETAIL

资讯详情

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

type-challenges 中等题 04182:在类型系统中用元组递归实现斐波那契序列 Fibonacci\<T\>

type-challenges 中等题 04182:在类型系统中用元组递归实现斐波那契序列 Fibonacci\<T\> 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载本题编号 04182中等难度要求我们在纯 TypeScript 类型系统内实现一个泛型FibonacciT输入一个数字T输出其对应的斐波那契数。在本文中我们将完整复现题目要求并给出基于「元组长度编码 递归展开」的完整可运行解法配合仓库中的模板、测试用例与相关题目源码深入讲解为什么类型系统里不能用算术、只能用元组长度来做加法以及如何用三个递归状态索引、前一项、当前项在编译期迭代出结果。读完本文你将掌握一套可复用的类型级计数器 递推范式可以举一反三解决MinusOne、ConstructTuple等同类题型。题目速览需求、序列与示例题目原文位于 questions/04182-medium-fibonacci-sequence/README.md核心需求一句话Implement a genericFibonacciTthat takes a numberTand returns its corresponding Fibonacci number.题目给出的序列起点是1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...示例type Result1 Fibonacci3 // 2 type Result2 Fibonacci8 // 21即Fibonacci3应展开为字面量类型2Fibonacci8应展开为21。注意该序列对下标≥ 1的位置与标准数学定义F(1)1, F(2)1, F(3)2 …完全一致只是题目省去了首项0的写法。难度与元信息见 questions/04182-medium-fibonacci-sequence/info.ymldifficulty: medium作者wind-liangGitHub 用户wind-liang。起点模板见 questions/04182-medium-fibonacci-sequence/template.ts全文只有一行占位实现type FibonacciT extends number any我们需要把这里的any替换为真实的类型逻辑。核心思路类型系统里没有算术就用元组长度来数数TypeScript 类型系统没有加减乘除也没有、-运算符。要在类型层面表示数字 1目前唯一通用、可靠的手段是把自然数编码为元组的长度数字N⟷ 一个长度为N的元组如[unknown, unknown]的长度是2数字N 1⟷[...Tuple, unknown]的长度数字相加 ⟷ 元组拼接[...A, ...B]的长度。这种手法在本仓库中随处可见属于官方认可的通用解法范式。例如 questions/07544-medium-construct-tuple/test-cases.ts 用ConstructTuple999[length]断言构造出长度为 999 的元组证明 TS 允许我们生成大长度的字面量元组并在其上取lengthquestions/02257-medium-minusone/test-cases.ts 则用MinusOne9_007_199_254_740_992这类超大数字练习元组长度运算。斐波那契的递推本质斐波那契序列满足递推式F(n) F(n-1) F(n-2)其中 F(1) F(2) 1用普通编程语言写一个循环只需三个变量当前索引i、前一项prev、当前项curr。类型系统里我们要做的就是把这个循环翻译成递归的类型其中循环变量用元组表示索引计数器Index元组长度代表已经算到第几项前一项Prev元组长度代表F(n-2)当前项Curr元组长度代表F(n-1)。每次递归做两件事判断Index[length]是否已经等于目标T等于则返回Curr[length]否则推进一轮Index追加一个元素Curr变成新的PrevPrev与Curr拼接作为新的Curr。完整解法与逐步推演下面是在template.ts基础上完成的解法含注释type Fibonacci T extends number, Index extends unknown[] [unknown], // 当前已推进到的索引初始为 1即 F(1) Prev extends unknown[] [], // 前一项的长度初始 F(0)按题意为 0 Curr extends unknown[] [unknown], // 当前项的长度初始 F(1) 1 Index[length] extends T ? Curr[length] : FibonacciT, [...Index, unknown], Curr, [...Prev, ...Curr]关键点说明T extends number约束输入为数字字面量默认参数让FibonacciT无需使用者传入任何辅助状态直接Fibonacci8即可终止条件Index[length] extends T当索引元组的长度命中目标T时Curr的长度就是答案递推分支Prev换为CurrCurr换为[...Prev, ...Curr]两段拼接长度即两数之和Index长度加一。手推Fibonacci3递归层级Index 长度Prev 长度Curr 长度是否命中 T3初始101否第 1 次递归211否第 2 次递归312是 → 返回 2得到Fibonacci3 2与题目示例一致。手推Fibonacci8Index 长度Prev 长度Curr 长度对应斐波那契项101F(1) 1211F(2) 1312F(3) 2423F(4) 3535F(5) 5658F(6) 87813F(7) 1381321F(8) 21✓关键细节剖析为什么不能用T本身直接递归减一T是一个number字面量类型例如8类型系统无法对它做T - 1。所以必须引入独立的索引元组Index通过[...Index, unknown]让元组长度自增再用Index[length] extends T做相等比较。这一用元组自增 长度比较的组合正是本仓库 questions/07544-medium-construct-tuple/template.ts 中ConstructTupleL extends number采用的同一套语言特性。为什么两个项也用元组而不直接用数字Curr[length]一旦被求值就是一个数字字面量无法再参与运算。因此我们把F(n-1)和F(n-2)都保持为元组形态靠[...Prev, ...Curr]完成类型层面的加法。这是整道题的灵魂加法 元组拼接数值 元组长度。初始化为什么是Index[unknown]、Curr[unknown]序列从F(1)1开始所以初始索引就是1[unknown]长度 1当前项初始为1对应F(1)Prev初始为[]长度 0充当F(0)这一哨兵保证第一轮拼接[...[], ...[unknown]]得到长度 1正确产出F(2)1。用仓库测试用例验证解法本仓库每个题目都自带类型级断言本题的验证位于 questions/04182-medium-fibonacci-sequence/test-cases.tsimport type { Equal, Expect } from type-challenges/utils type cases [ ExpectEqualFibonacci1, 1, ExpectEqualFibonacci2, 1, ExpectEqualFibonacci3, 2, ExpectEqualFibonacci8, 21, ]把上面的解法填入template.ts后该文件应能通过类型检查没有任何编译错误因为EqualX, Y是严格类型相等判断其实现见 utils/index.d.ts 第 7–9 行基于著名的函数可赋值性技巧(T() T extends X ? 1 : 2) extends (T() T extends Y ? 1 : 2)可区分绝大多数看起来一样的类型ExpectT extends true要求传入true见 utils/index.d.ts 第 1 行任何不相等都会被判定为类型错误四个断言分别覆盖F(1)、F(2)、F(3)、F(8)既验证了递推的起点也验证了多次迭代后的结果。Equal/Expect由工作区依赖type-challenges/utils提供其包配置见 utils/package.json。仓库根目录 package.json 声明了typescript^5.3.3等依赖本地验证时在仓库根目录安装依赖后如pnpm install让tsc检查questions/04182-medium-fibonacci-sequence/test-cases.ts即可确认解法通过存在任何Expect...报错即代表未通过。边界与进阶讨论序列起点题目序列写作1, 1, 2, 3, …但Fibonacci1、Fibonacci2均为1与标准定义在n ≥ 1时完全等价解法无需特判。递归深度该解法每推进一项就产生一层递归同时元组Curr的长度随项数指数增长。TypeScript 编译器对递归实例化和元组展开有自身深度限制因此本解法在T较小时几十项以内工作良好这一点与仓库中 questions/07544-medium-construct-tuple/test-cases.ts 用ts-expect-error标注ConstructTuple1000超限的思路一致——类型层面的数值运算是有编译器资源上限的属于 TypeScript 类型编程的固有约束而非本题特有的缺陷。范式复用Index元组计数、Prev/Curr双滚动变量的写法可以直接迁移到类型级数组遍历、MinusOne见 questions/02257-medium-minusone/template.ts 的元组减一思路、累加器型递归如Sum、Multiply等极难题等场景是 type-challenges 中等难度段最具性价比的通用技巧之一。小结FibonacciT表面是一道数学题实际上考察的是 TypeScript 类型编程的两项基本功用元组长度编码自然数以及用递归参数携带循环状态。掌握「计数器元组 两项滚动累加」这一模式后你不仅能解出本题还能顺势吃透仓库中MinusOne、ConstructTuple等一批同类题目为挑战 harder / extreme 级别的数值运算题打下坚实基础。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐用 JavaScript 递归实战斐波那契数列与归并排序Fibonacci Merge Sort用 JavaScript 递归实战斐波那契数列与归并排序Fibonacci Merge Sort 导读 本篇实战项目来自 curriculum htt文档教程教育Type Challenges项目中的斐波那契序列类型实现解析Type Challenges项目中的斐波那契序列类型实现解析 在TypeScript类型编程领域Type Challenges项目提供了一个极佳的平台来练习示例工程从数学到类型Type-Challenges斐波那契数列的优雅实现从数学到类型Type Challenges斐波那契数列的优雅实现 你是否曾困惑于如何在TypeScript类型系统中实现数学逻辑当普通函数轻松解决的斐波那契示例工程上一篇全网视频资源下载神器3分钟快速掌握res-downloader终极指南下一篇如何轻松下载B站视频解锁大会员4K与充电专属内容创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表