如何在TypeScript中编写Includes类型定义?
如何在TypeScript中编写Includes类型定义?
看起来你在实现TypeScript类型系统版的Array.includes时踩了个小坑——明明数组里只有boolean类型元素,却把false判定为存在,这确实有点反直觉。让我帮你拆解问题所在,再给出可行的修复方案。
问题出在哪?
先看你的测试用例:type Test = Includes<[boolean, 2, 3, 5, 6, 7], false>,你期望返回false,但当前代码返回了true,核心原因有两个:
- 分布式条件类型的干扰:TypeScript的条件类型在处理联合类型时会自动“展开”判断。当
First是boolean(本质是true | false的联合类型),U是false时,U extends First会拆成false extends true和false extends false两个判断,其中后者成立,所以会进入后续分支。 - 子类型判断≠严格类型相等:你用双向
extends试图模拟类型相等,但extends判断的是“子类型关系”,不是“两个类型完全相同”。比如false extends boolean成立,但boolean extends false不成立,但因为联合类型的分布式展开,这里会出现部分匹配的情况,导致最终返回true。
修复方案:用严格类型相等判断
要实现符合预期的Includes,我们需要先定义一个能判断两个类型严格相等的工具类型,再结合数组遍历逻辑实现。
首先实现严格相等的Equal类型(这是TypeScript类型编程里常用的技巧):
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
这个类型通过比较两个泛型函数的类型是否一致,来判断X和Y是否严格相等,能避开分布式条件类型的干扰,准确识别字面量类型和其基础类型的差异(比如false和boolean是不同的)。
然后修改你的Includes类型:
type Includes<T extends any[], U> = T extends [infer First, ...infer Rest] ? Equal<First, U> extends true ? true : Includes<Rest, U> : false;
现在再测试你的用例:
type Test = Includes<[boolean, 2, 3, 5, 6, 7], false>; // 返回 false,符合预期 type Test2 = Includes<[false, 2, 3], false>; // 返回 true,符合预期 type Test3 = Includes<[boolean], boolean>; // 返回 true,符合预期
为什么这个方案能行?
Equal类型通过泛型函数的类型匹配,绕过了分布式条件类型的展开,精准判断两个类型是否完全一致。- 遍历数组时,每一步都用严格相等判断当前元素类型和目标类型,只有完全匹配才返回
true,否则递归处理剩余元素,遍历完所有元素都没匹配就返回false,完美模拟了JavaScriptArray.includes的严格相等(===)行为。
备注:内容来源于stack exchange,提问作者kristin lee
相关产品推荐
相关产品推荐

