拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Type Challenges(type-challenges):在 TypeScript 类型系统上刷题通关的完整指南

Type Challenges(type-challenges):在 TypeScript 类型系统上刷题通关的完整指南
  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载

Type Challenges 是一个以 TypeScript 类型系统为“竞技场”的开源题库项目,它通过大量难度分级的类型编程挑战,帮助你亲手实现Pick、Omit、Readonly等类型工具,深入理解条件类型、infer、模板字面量类型与递归等进阶机制。本文以仓库中的巴西葡萄牙语版 README(README.pt-BR.md)为主线,结合 scripts/generate-play.ts、scripts/loader.ts、utils/index.d.ts 等源码与题目目录结构,完整讲解项目的定位、题库组织方式、本地 Playground 搭建与运行流程、贡献路径及配套学习资源。

项目定位:用“在线判题”的方式修炼类型功夫

“pelo poder do conhecido sistema de tipos Turing Completed do TypeScript”(借助 TypeScript 那出了名的图灵完备类型系统的力量)——这句被 README 以<del>删除线标记的引言,恰好道出了项目的初衷:TypeScript 的类型层并不是“够用就行”的附属品,而是一个可以像普通编程语言一样表达算法、推演逻辑的完整体系。

项目的核心理念在README.pt-BR.md的 Intro 一节说得很直白:

  • 高质量的类型定义能显著提升项目的可维护性,并在编译期拦截潜在 bug;
  • 项目鼓励你亲手编写自己的类型工具,在解决挑战的过程中理解类型系统“如何工作”;
  • 项目同时致力于营造一个社区,你在真实项目中遇到的类型难题可以提出来,它们甚至可能成为新的挑战题目。

也就是说,这是一个“从实战中来、到实战中去”的类型编程训练营:真实世界里踩过的坑,经过沉淀后会反哺为题库里的一道新题。仓库里每个题目目录都包含info.yml(题目元信息)、template.ts(待填空的模板)、test-cases.ts(判题测试)与多语言README.*.md,从 questions/00002-medium-return-type/ 这类目录就能直观看到这种“一题一目录”的组织方式。

挑战题库:五级难度 + 标签检索

难度分级与数量

README 用徽章(badge)将题库划分为五个梯度,鼠标点击即可跳转到对应题目:

难度徽章配色题目数(README 标注)示例题目
aquecimento(热身)teal113・Hello World
fácil(简单)绿色13Pick、Readonly、Exclude、Awaited、Concat、Includes
médio(中等)橙色104Return Type、Omit、Deep Readonly、Flatten、IndexOf、KebabCase
difícil(困难)红色55Currying 1、Union to Intersection、CamelCase、FizzBuzz、Sudoku
extremo(极限)紫色17Query String Parser、Slice、JSON Parser、Sort、Sum

注意:README 明确说明,所有挑战都在 TypeScript 的 strict mode 中的"strict": true配置完全一致,同时该配置还开启了noImplicitReturns、noUnusedParameters等严格检查,确保答案在严格类型约束下才有意义。

三种浏览视角

README 为 190 道题目提供了三种导航方式,可折叠展示:

  1. 按难度浏览:五档难度徽章直接排列,每道题以题目编号・英文题名徽章呈现,如4・Pick、2・Obter Tipo de Retorno(葡语题名)。
  2. 按标签浏览(Por Tags):题库覆盖#JSON、#array、#string、#template-literal、#infer、#recursion、#union、#tuple、#object、#promise、#vue、#math等大量主题标签。以#infer为例,可找到Parameters、Get Return Type、Union to Intersection、Inclusive Range、Sort等递进题目——这正是“从简单到极限”的成长路径。
  3. 按纯文本列表浏览(Por Texto Simples):按难度分组的完整题名清单,适合快速扫描。

题目结构与判题原理:一题一目录

在开始做题之前,先理解一个题目目录里到底装了什么。以 questions/00002-medium-return-type/ 为例,每个目录包含四个核心文件:

  • README.md/README.pt-BR.md等:题面描述(含多语言版本);
  • info.yml:题目元信息,声明title、author、tsconfig、original_issues、recommended_solutions、tags、related等字段,具体结构可参考 scripts/types.ts 中的QuizMetaInfo接口定义;
  • template.ts:待你完成的类型模板。例如 Return Type 一题的初始内容只有一行type MyReturnType<T> = any,任务就是把any换成正确的类型推导实现;
  • test-cases.ts:判题测试,使用@type-challenges/utils提供的断言工具(如Expect、Equal、ExpectExtends)验证你的实现。

这里需要特别说明判题工具链的底层实现:utils/index.d.ts 是仓库自研的断言库(对应@type-challenges/utils包,见 utils/package.json),核心断言基于一个非常经典的类型等价性技巧:

export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false

这个写法利用“惰性条件类型在函数签名中的同构性”来判断两个类型是否完全相等;Expect<T extends true> = T则把断言结果“翻译”成编译期类型错误。打开任意一道题的 test-cases.ts,你会看到大量形如type cases = [Expect<Equal<MyReturnType<() => string>, string>>, ...]的断言数组——只有你的实现让所有断言全部通过,题目才算真正解出。

本地运行:三分钟搭起你的专属 Playground

前置环境

按 README 的 “Execute Localmente” 章节,你需要准备:

  • 最新版本的 Node.js;
  • 包管理器 pnpm 中packageManager声明为pnpm@8.12.1)。

第一步:安装依赖

克隆仓库后,在仓库根目录执行:

pnpm install

第二步:生成本地 Playground

pnpm generate

脚本会以交互式下拉菜单询问你要使用的语言(支持en、zh-CN、ja、ko、pt-BR五种,见 scripts/locales.ts 中的supportedLocales定义)。选择完成后,所有题目会被生成到仓库的./playground目录,并按难度分子目录存放(如playground/easy、playground/medium)。之后你就可以用任意支持 TypeScript 的 IDE 或编辑器打开对应.ts文件开始做题。

从 scripts/generate-play.ts 的源码可以看出这个生成过程的几个关键行为:

  • 每道题会通过formatToCode被组装成一个完整可运行的.ts文件,内容依次是“题面注释(含信息头)→ 模板代码 → 测试用例 → 进一步指引注释”,组装逻辑见 scripts/actions/utils/formatToCode.ts;
  • 如果某个题目没有你选择的语言版本,脚本会打印... has no {LOCALE} version. Skipping并跳过该题(对应loader.ts中loadLocaleVariations的“缺失时回退到默认英文版”策略);
  • 如果playground目录已经存在(可能包含你写过的答案),脚本会先弹出确认框,询问是否覆盖。

第三步:更新 Playground 且保留你的作答

做题过程中题目可能会更新或新增,此时若直接重新pnpm generate会覆盖你已写的答案。README 提供了保留修改的生成方式:

pnpm generate --keep-changes

或等价的简写:

pnpm generate -K

该机制的源码实现在generate-play.ts中:脚本会先对playground现有文件计算 SHA-1 哈希快照(takeSnapshot),与上次生成时写入的.playgroundcache缓存比对,只有哈希未变化的文件才会被判定为“可覆盖”;你的作答文件因哈希已改变而得以保留,同时新增题目会被安全地写入。

其他入口:在线 Playground 与 VS Code 扩展

除了本地做题,README 还提供了两条零配置路径:

  • TypeScript Playground:点击 README 中的 🔥 徽章即可在官方 Playground 中启动挑战(需安装@type-challenges/playground-plugin插件);
  • VS Code 扩展:通过YRM.type-challenges扩展可以在编辑器内直接浏览与解答挑战。

深入理解:题目、元信息与多语言是如何被加载的

README 只描述了“怎么用”,而 scripts/loader.ts 揭示了背后的加载管线,理解它有助于你读懂题目目录的设计意图:

  • loadQuizzes()使用 fast-glob 以{0..9}*-*模式扫描 questions/ 目录下的所有题目文件夹;
  • 每个文件夹按编号-难度-题名slug命名,如00002-medium-return-type,loadQuiz()会从中解析出题号no与难度difficulty(warm | easy | medium | hard | extreme | pending,见 scripts/types.ts);
  • loadLocaleVariations()会为每个文件寻找README.zh-CN.md、README.pt-BR.md等同名前缀的多语言变体,并在缺失时回退到默认英文版;
  • info.yml使用 js-yaml 解析,其中tags、related字段支持逗号分隔的字符串写法,会被自动归一化为数组。

这套加载管线同时服务于本地 Playground 生成与 GitHub Actions 自动化流程(见 scripts/actions/issue-pr.ts)——当社区成员以 Issue 形式提交新题时,机器人会按模板解析出Info / Template / Test Cases三个代码块,自动创建包含题目目录、README、template.ts与test-cases.ts的 Pull Request,并生成可预览的 Playground 链接。这就是 README 所说“真实问题可以成为新挑战”的自动化实现。

如何贡献:不止是提交答案

README.pt-BR.md的 “Como Contribuir” 章节列出了七种参与方式:

  1. 分享你的答案 / 解法;
  2. 提出新挑战;
  3. 为已有挑战补充更多测试用例;
  4. 提供学习资料或解题思路;
  5. 分享你在真实项目中遇到(无论是否已解决)的类型问题,社区会一起帮忙,甚至将其发展为新题目;
  6. 在 Issue 讨论中帮助他人;
  7. 参与项目基础设施的建设——参考 TODOs.md。

参与方式也很简单:打开一个 Issue 并选择对应的模板即可。结合上文可知,若你提交的 Issue 带有new-challenge标签,自动化机器人会直接帮你把题目落地成 PR,你只需在 Issue 中按模板填写 YAML 元信息、模板代码与测试用例。

推荐学习路线:从官方文档到社区资源

README 为新手到进阶者整理了一份完整的学习清单,覆盖官方文档、文章、演讲、解决方案仓库与书籍:

  • 官方文档(Oficial):TypeScript Handbook 中的 Unions/Intersection Types、Literal Types、Utility Types 与 Advanced Types 章节,以及新版 Handbook;
  • 文章(Artigos):Learn Advanced TypeScript Types、The Art of Type Programming、Type Query: jQuery Style Type Manipulation、TypeScript Deep Dive;
  • 演讲(Palestras):Type Level Programming in Typescript;
  • 项目 / 解法(Projetos / Soluções):全挑战的视频讲解与解法清单、Type Challenges Solutions、Type Gymnastics、TypeType Examples 等;
  • 书籍(Livros):Effective TypeScript、Learning TypeScript、TypeScript in 50 Lessons、TypeScript Cookbook。

一个建议的学习路径是:先在官方 Handbook 中补齐条件类型、映射类型、infer、模板字面量类型等基础概念,然后从fácil难度开始逐步推进,配合题目的test-cases.ts理解判题要求,遇到卡点再回到源码与社区解法中对照。

项目背后的故事与许可

README 提到,这个项目诞生于维护者与 @hardfist 显示项目以 MIT 协议开源,作者为 Anthony Fu,并采用 pnpm workspace 管理(根目录 pnpm-workspace.yaml),其中@type-challenges/utils与@type-challenges/scripts都是仓库内部的独立包。

总结

Type Challenges 的价值在于把“理解类型系统”从被动阅读变成了主动闯关:每个目录都是“题面 + 模板 + 断言测试”的完整闭环,pnpm generate一键生成本地 Playground 让你在熟悉的 IDE 中作答,--keep-changes保证你的进度不被覆盖,而 GitHub Actions 自动化让新题可以持续流入题库。无论你是想夯实类型基本功、备战严格模式下的类型体操面试,还是想用类型系统解决真实项目中的建模难题,从questions/目录挑一道题、填好template.ts、让test-cases.ts里的断言全部通过,就是最好的起点。

  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载
上一篇:ComfyUI 中文工作流预设:21 个模板,从导入 JSON 到出图一次跑通
下一篇:Symfony Cache Contracts 使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表