)
示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载导读AnyOf是 type-challenges 仓库中编号为 949 的一道 medium 难度数组#array类型挑战要求我们在纯类型层面实现一个类似 Python 内置any()的类型工具输入一个数组类型只要其中存在真值元素就返回true否则返回false。阅读本文后你将掌握条件类型递归、infer推断、T[number]联合索引取值等核心技法并理解真值truthy判定在类型系统中的准确表达方式——这背后还隐藏着 JS 与 Python 真值语义的分歧是本次挑战最值得深挖的知识点。题目速览要求、模板与示例题目原文位于 questions/00949-medium-anyof/README.md难度与标签在 info.yml 中标注为difficulty: medium、tags: array作者为kynefuk。核心要求英文原文Implement Python likedanyfunction in the type system. A type takes the Array and returnstrueif any element of the Array is true. If the Array is empty, returnfalse.翻译过来即在类型系统中实现类似 Python 的any函数。类型接收一个数组若数组中任一元素为真则返回true否则返回false空数组返回false。题目给出的起点模板位于 template.tstype AnyOfT extends readonly any[] any我们只需将 any替换为真正的类型逻辑。题目示例type Sample1 AnyOf[1, , false, [], {}] // expected to be true. type Sample2 AnyOf[0, , false, [], {}] // expected to be false.第一个数组里有1这个真值元素所以为true第二个数组所有元素0、、false、[]、{}都不是真值所以为false。真值语义辨析挑战遵循的是 Python 规则而非 JavaScript 规则这是本题最容易踩坑、也最值得先想清楚的一点。在JavaScript 运行时中[]空数组和{}空对象都是真值truthy——Boolean([])和Boolean({})均为true。若按 JS 语义[0, , false, [], {}]应判定为存在真值[]、{}都是真值结果应为true。但题目示例给出的期望结果是false且第 9 组测试用例ExpectEqualAnyOf[0, , false, [], {}, undefined, null], false见 test-cases.ts也要求[]、{}连同undefined、null全部视为假值。这说明本题遵循 Python 的真值语义Python 中空列表[]、空字典{}都是 falsy这与 JS 截然不同。因此我们必须在类型系统中把假值集合定义为0 | | false | [] | {} | undefined | null即0、空字符串、false、空元组、空对象、undefined、null。一个关键陷阱不能直接用{}表示空对象直觉上我们想直接写Falsy 0 | | false | [] | {} | undefined | null但{}在 TypeScript 中几乎匹配一切非空值{ name: test }、[1]、1都 extends{}。一旦把裸{}放进假值联合{ name: test } extends Falsy就会判定为真从而被错误地当成假值导致测试用例ExpectEqualAnyOf[0, , false, [], { name: test }], true失败。正确的空对象表达方式是Recordstring, never等价于{ [key: string]: never }它要求所有字符串键的属性值都是never而{ name: test }的name属性是string类型无法满足never因此不会被误判为空对象。空对象类型{}由于不含任何属性可空满足该索引签名约束从而正确落入假值集合。解题思路条件类型 infer 递归拿到一个T extends readonly any[]的元组类型最直观的做法是逐个剥离头部元素用T extends [infer F, ...infer R]把首个元素推断为F、剩余部分推断为R然后递归处理剩余元素。递归的终止条件是T无法再匹配[infer F, ...infer R]即已到空元组此时返回false。判断逻辑可以这样抽象若当前元素F是假值F extends Falsy成立则结果取决于剩余元素——继续递归若当前元素F是真值立即返回true短路无需再看后面递归到空元组时返回false。实现一递归逐元素判定type Falsy 0 | | false | [] | Recordstring, never | null | undefined type AnyOfT extends readonly any[] T extends [infer F, ...infer R] ? F extends Falsy ? AnyOfR : true : false逐用例走查AnyOf[1, , false, [], {}]1 extends Falsy不成立 → 直接返回true。✅AnyOf[0, , false, [], {}]0、、false、[]空元组 extends[]、{}空对象 extendsRecordstring, never全部是假值 → 递归到空元组 → 返回false。✅AnyOf[0, test, false, [], {}]遇到test非假值→ 返回true。✅AnyOf[0, , false, [], {}, undefined, null]逐项皆为假值 →false。✅AnyOf[][] extends [infer F, ...infer R]不成立空元组拆不出F→ 返回false。✅实现二T[number]联合索引 整体判断更简洁利用元组的索引访问T[number]可以直接取出所有元素类型组成的联合。此时任一元素为真等价于这个联合不是假值联合的子类型type Falsy 0 | | false | [] | Recordstring, never | null | undefined type AnyOfT extends readonly any[] T[number] extends Falsy ? false : true判定逻辑X extends Y要求联合X的每一个成员都 extendsY。因此若T[number]联合中的每一个成员都是假值则整个联合 extendsFalsy成立返回false只要有一个真值成员如1、test、[1]、{ name: test }不满足 extends整体返回true。特别地空元组[]的T[number]是never而never extends Falsy恒成立天然返回false——空数组场景被优雅地覆盖无需显式特判。这种写法利用联合的 extends 是全成员约束这一特性代码量最少。两种实现的取舍与边界提醒递归版实现一语义直白、易于扩展可在递归过程中附带累计状态但存在类型递归深度限制遇到极长元组时可能触发 Type instantiation is excessively deep 报错。联合版实现二无递归、更简洁是社区常见的高票解法。共同边界当元素类型包含any时如AnyOf[any]any extends Falsy ? ... : ...会同时命中两个分支得到boolean结果失去精确性。题目测试用例未涉及any元素但作为工程实践值得留意。用测试用例逐条验证挑战的自动化判题机制type-challenges 的每个挑战都自带一个类型断言测试文件。本题的 test-cases.ts 共 10 组断言覆盖了输入期望覆盖点[1, test, true, [1], { name: test }, { 1: test }]true数字、字符串、布尔、非空元组、字符串键对象、数字键对象均为真值[1, , false, [], {}]true混合输入下存在1[0, test, false, [], {}]true混合输入下存在test[0, , true, [], {}]true存在true[0, , false, [1], {}]true非空元组[1]为真值[0, , false, [], { name: test }]true非空对象为真值[0, , false, [], { 1: test }]true数字键非空对象为真值[0, , false, [], { name: test }, { 1: test }]true同时存在两个真值对象[0, , false, [], {}, undefined, null]false全套假值集合[]false空数组每条断言都写成ExpectEqualAnyOf..., true | false的形式其中Expect与Equal定义在 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 : falseEqual利用泛型函数参数位置的逆变/协变差异做结构级严格相等比较能区分any与其他类型见 utils/index.d.test.ts 中ExpectFalseEqualany, 123的断言Expect...则要求传入的必须是true字面量一旦AnyOf推断错误Equal返回falseExpectfalse即编译报错从而实现类型即测试。这些工具类型以type-challenges/utils包形式发布见 utils/package.json并在根目录 package.json 中以workspace:*方式作为开发依赖引入。本地验证如何亲手跑通这道题仓库是纯类型挑战验证方式即 TypeScript 编译检查。操作步骤将你的解答写入 questions/00949-medium-anyof/template.ts把type AnyOfT extends readonly any[] any替换为实现。在仓库根目录安装依赖pnpm install仓库使用pnpm8.12.1见 package.json 的packageManager字段使type-challenges/utils工作区包可被解析。运行类型检查例如npx tsc --noEmit。项目根目录 tsconfig.json 继承 tsconfig.base.json其中开启了strict: true、lib: [ESNext]、moduleResolution: node等选项测试文件 test-cases.ts 中的任何ExpectEqual...断言失败都会体现为编译错误。若编译零报错说明 10 组用例全部通过挑战完成。小结本题收获的三个知识点递归 infer是元组处理的基础范式T extends [infer F, ...infer R]模式在 LengthOfString、TupleToUnion、Reverse 等大量挑战中反复出现是类型体操的基本功。T[number]联合索引的妙用把元组压成联合再整体判断可以免去显式递归并天然处理空数组never extends X恒真。真值判定要明确语义基准本挑战采用 Python 式真值空容器为假与 JS 运行时语义不同且空对象必须用Recordstring, never表达裸{}会因匹配一切对象而失效。这提醒我们在类型系统里复刻运行语义时必须逐一厘清边界值并用 test-cases.ts 的断言反向校验。本文的讲解基于当前仓库的 题目 README另有 简体中文版、template.ts、test-cases.ts 与 utils/index.d.ts 等源码与配置读者可直接在仓库内对照阅读。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐type-challenges 高级实战实现 IsAny 工具类型在 TypeScript 中精确检测 any 类型type challenges 高级实战实现 IsAny 工具类型在 TypeScript 中精确检测 any 类型 本篇技术指南围绕 type chall示例工程PyTorch Examples 仓库深度解读用 DCGAN 实现无监督表示学习PyTorch Examples 仓库深度解读用 DCGAN 实现无监督表示学习 导读 本文以 dcgan/README.md https://link.gi示例工程Type Challengestype-challenges在 TypeScript 类型系统上刷题通关的完整指南Type Challengestype challenges在 TypeScript 类型系统上刷题通关的完整指南 Type Challenges 是一个示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考