ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

type-challenges 第 19749 题 IsEqual:用类型体操实现类型相等判定

2026/10/2 13:48:06 拓冰建站 浏览量
type-challenges 第 19749 题 IsEqual:用类型体操实现类型相等判定 示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载导读本文聚焦 type-challengesCollection of TypeScript type challenges with online judge中等难度题目19749-medium-isequal讲解如何实现一个返回布尔类型的类型相等判断工具IsEqualX, Y。你将掌握 TypeScript 类型系统中严格相等判定的核心技巧——利用泛型函数与条件类型的分配性绕过any、联合类型与never的陷阱并读懂仓库中 utils/index.d.ts 提供的官方Equal实现与其测试用例。题目背景在类型系统里实现 IsEqual的目标非常直观像运行时 JavaScript 的运算符一样判断两个给定的类型是否相等并返回true或false。原题定义与示例见 questions/19749-medium-isequal/README.mdtype X1 1 type Y1 1 type T1 IsEqualX1, Y1 // expected to be true type X2 1 type Y2 2 type T2 IsEqualX2, Y2 // expected to be false题目属于#utils工具类型分类见 info.yml难度为 medium作者是 Takahiro KatoGitHub: doz13189。这看似简单的要求背后却隐藏着类型系统里最经典的难题之一。为什么不能直接写X extends Y ? ... : ...许多初学者会先尝试最朴素的双向extends判定type IsEqualX, Y X extends Y ? (Y extends X ? true : false) : false这种写法在大多数普通类型上确实有效但在类型系统的边角情况下会给出错误答案。仓库的测试用例 test-cases.ts 精确地划定了正确实现必须满足的判定边界import type { Equal, Expect } from type-challenges/utils type cases [ ExpectEqualIsEqualnumber, string, false, ExpectEqualIsEqual1, 1, true, ExpectEqualIsEqualany, 1, false, // any 不能被误判为 1 ExpectEqualIsEqual1 | 2, 1, false, // 联合类型 1 | 2 不能被误判为 1 ExpectEqualIsEqualany, never, false, // any 不能被误判为 never ExpectEqualIsEqual[any], [number], false, // 元素类型 any 与 number 必须区分 ]这里给出了四个必须被正确区分的危险组合IsEqualany, 1必须为falseany在条件类型中具有特殊的双向赋值兼容性any extends 1与1 extends any都会成立IsEqual1 | 2, 1必须为false裸类型参数在条件类型中会被分配distribute1 | 2 extends 1会被拆开逐项判定导致结果失真IsEqualany, never必须为falseany与never在extends判定中都会表现得两边都成立或产生分配行为容易被混为一谈IsEqual[any], [number]必须为false即使外层包裹成元组禁用分配性元素内部的any与number仍需要被严格区分。可见题目表面是判断相等实际考验的是对any、联合类型分配性与never这些 TypeScript 类型系统陷阱的深刻理解。权威解法官方Equal的泛型函数技巧type-challenges 仓库其实已经给出了这道题的标准答案——它不是直接写在题目模板里而是沉淀在工具库 utils/index.d.ts 中被所有题目的测试用例广泛引用export type EqualX, Y (T() T extends X ? 1 : 2) extends (T() T extends Y ? 1 : 2) ? true : false原理剖析这个解法的核心思路是不直接比较X与Y而是比较以X或Y为条件约束的两个泛型函数类型是否互相可赋值。构造一个不接受参数、返回条件类型的泛型函数签名(T() T extends X ? 1 : 2)其返回类型由X决定对X和Y分别构造然后判断两个函数类型是否满足extends可赋值关系函数签名的比较是结构化的、非分配的因此绕开了裸类型参数被分配展开的问题any无法穿透这种函数签名比较any参与比较时TS 不会让any extends 1之类的宽松兼容悄悄成立从而能精确区分any与具体类型同理[any]与[number]作为元组时函数签名比较会逐层走到元素类型any与number的差异会被严格暴露出来。简言之把类型相等转化为两个函数类型的可赋值性比较利用函数签名的非分配、非宽松特性得到比extends双向判定严格得多的相等性语义。仓库中的实测证据工具库自带的自检测试 utils/index.d.test.ts 验证了Equal的严格性ExpectEqualtrue, true, ExpectFalseEqualfalse, true, ExpectEqual123, 123, ExpectFalseEqual123, string, ExpectEqual{ a: number }, { a: number }, ExpectFalseEqual{ a: number }, { b: number }, ExpectFalseEqualany, 123, ExpectFalseEqualany, unknown,注意最后两行Equalany, 123与Equalany, unknown都必须为false。这再次印证了any的幽灵属性——它既不等于任何具体类型也不等于unknown只有泛型函数签名技巧能稳定地把它识别出来。动手实现把Equal移植到本题模板题目的解题入口是模板文件 template.ts初始状态下它只是一个占位type IsEqualX, Y any你需要将其替换为真正的实现。最直接的做法就是把官方Equal的思路搬到模板中type IsEqualX, Y (T() T extends X ? 1 : 2) extends (T() T extends Y ? 1 : 2) ? true : false替换后用 test-cases.ts 中的 6 组断言验证全部通过即代表实现正确。进阶阅读与NotEqual、IsAny的配合在工具库 utils/index.d.ts 中Equal还被进一步封装NotEqualX, Yutils/index.d.ts在Equal基础上取反用于判断不相等export type NotEqualX, Y true extends EqualX, Y ? false : trueIsAnyTutils/index.d.ts专门检测any其实现为0 extends (1 T) ? true : false利用any与任何交叉类型兼容的特性AlikeX, Yutils/index.d.ts则是宽松相等先通过MergeInsertions将交叉类型展开后再用Equal比较用于判定{ a: 1 } { b: 2 }与{ a: 1, b: 2 }这类结构等价但不严格相等的情况对应测试见 utils/index.d.test.ts。理解了IsEqual你就能顺带掌握整套相等性判断工具链的设计思想。如何在本地运行与验证type-challenges 仓库以 pnpm workspace 管理见 package.json 与type-challenges/utils的 workspace 依赖。在仓库根目录下可以按以下方式验证# 安装依赖pnpm 8.12.1见 package.json packageManager 字段 pnpm install # 对题目做类型级测试将 template.ts 中的实现填写完毕后 # 用 tsc 对 test-cases.ts 做类型检查即可tsconfig 位于根目录 tsconfig.json pnpm exec tsc --noEmit questions/19749-medium-isequal/test-cases.ts当实现正确时Expect...中的条件全部为true类型检查零报错一旦实现退化为朴素的X extends Y双向判定any、联合类型相关的断言就会立刻报错帮助你直观感受两种实现的差异。小结IsEqual是 TypeScript 类型体操中最经典的中等难度题目之一。它教会我们三件事类型相等不能靠朴素的extends双向判定any、联合类型分配与never会制造大量假阳性将类型包装进泛型函数签名再比较可赋值性是获得严格相等语义的通用武器仓库中的 utils/index.d.ts 把这套技巧固化为官方Equal并通过 utils/index.d.test.ts 留下了可长期回归的测试资产——这也是 type-challenges 项目答案即工具、工具即题库的设计缩影。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐type-challenges 中等题 02257用类型体操实现 MinusOne正整数减一type challenges 中等题 02257用类型体操实现 MinusOne正整数减一 导读 MinusOne 是 type challenges示例工程type-challenges 第 949 题 AnyOf在类型系统里实现类 Python any 的真值判定type challenges 第 949 题 AnyOf在类型系统里实现类 Python any 的真值判定 本题来自 type challenges ht示例工程TypeScript 类型体操用模板字面量类型实现 IntegerT 整数判别type-challenges 10969TypeScript 类型体操用模板字面量类型实现 IntegerT 整数判别type challenges 10969 本文围绕 type chall示例工程上一篇.NET Mono Ahead-of-Time (AOT) 编译完全指南从 --aot 到 Full AOT、LLVM 与交叉编译下一篇CANN opbase 中 aclnnFinalize 接口详解单算子 API 执行框架的资源去初始化与进程安全退出创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考