You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中Equal类型判断两类型是否相同的原理及测试代码问题解析

理解TypeScript的Equal类型原理及测试代码问题

这是个非常典型的TypeScript高级类型问题,咱们拆成两部分来解释:

一、Equal<X, Y>类型的工作原理

先再看一遍这个类型定义:

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

它的核心思路是利用泛型函数类型的兼容性来判断两个类型是否完全一致,背后依赖TypeScript类型系统的两个关键特性:

  1. 泛型参数的非分布式条件类型:
    当T是未指定的泛型参数时,T extends X不会触发条件类型的分布式特性(只有T是联合类型时才会逐个展开判断)。这意味着我们是在判断“任意类型T是否能匹配X”,而非拆分联合类型成员单独判断。

  2. 函数类型的严格兼容性判断:
    TypeScript在对比两个函数类型时,会逐一校验参数和返回值的类型逻辑。这里的两个泛型函数<T>() => T extends X ? 1 : 2和<T>() => T extends Y ? 1 : 2,只有当X和Y完全相同时,它们的返回值逻辑才会完全一致,整个函数类型才会被判定为兼容。

举几个实际例子:

  • Equal<number, number>返回true,因为两个泛型函数的返回值逻辑完全匹配;
  • Equal<number, string>返回false,当T为number时,第一个函数返回1,第二个返回2,函数类型不兼容;
  • 它能正确处理any的特殊情况:Equal<any, number>返回false,而简单的双向extends判断会错误返回true(因为any可以匹配任意类型)。

二、你的测试代码赋值不合法的原因

先明确Foo<X>的定义:

type Foo<X> = <T>() => T extends X ? 1 : 2;

这是一个泛型函数类型——它不是指“返回某类值的函数”,而是“本身带有泛型参数T的函数,返回值类型由T和X的关系决定”。

你的赋值操作全部不合法,主要有两个核心原因:

1. 赋值的是非函数值,类型完全不匹配

比如:

var a: Foo<number> = true; // ❌ true是布尔值,不是函数类型
var d: Foo<number> = 42;  // ❌ 42是数字,不是函数类型

Foo<X>要求的是函数类型,你传入的是原始类型值,自然会触发类型不兼容报错。

2. 赋值的是普通函数,不符合泛型函数类型要求

比如:

var g: Foo<number> = () => true; // ❌ 这是无泛型参数的普通函数,不符合要求

Foo<number>要求的是带有泛型参数T的函数,而你写的() => true没有泛型参数,类型层面完全不匹配。

正确的赋值方式

要满足Foo<X>的类型要求,你需要定义一个泛型函数,比如:

// 类型层面合法的赋值(运行时因类型擦除,无法真正根据T返回对应值,所以用类型断言)
const validFooNumber: Foo<number> = <T>() => 1 as T extends number ? 1 : 2;

// 针对Foo<any>的简化写法(T extends any始终为true,返回1符合类型要求)
const validFooAny: Foo<any> = <T>() => 1;

这样定义的泛型函数,才会被TypeScript判定为符合Foo<X>的类型定义。


内容的提问来源于stack exchange,提问作者xiong35

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:03:11