跳到主要内容

extends 条件类型怎么定义?

下文默认基于 TypeScript 5.x,并假设开启 strict: true

面试速答(30 秒版 TL;DR)

  • 条件类型的基本语法是:
T extends U ? X : Y
  • 含义是:如果 T 可以赋值给 U,结果就是 X,否则就是 Y
  • 它常用来做:
    • 类型分支判断;
    • 联合类型过滤;
    • 提取函数参数、返回值;
    • 配合 infer 做类型推导。
  • 面试里要补一句:
    • 这里的 extends 不是“继承实现”,而是“类型约束/可赋值关系判断”。

心智模型:在类型系统里写 if...else

1. 最基础的定义方式

type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

标准解释:

  • IsString<T> 是一个条件类型;
  • T 满足 extends string 时返回 true
  • 否则返回 false

2. 为什么它叫“条件类型”

因为它跟运行时的三元表达式很像:

condition ? a : b;

只是这里判断的不是值,而是类型关系

所以可以把它理解成:

  • 运行时里你写 if
  • 类型系统里你写 extends ? :

3. 常见用法一:按条件返回不同结构

type WrapIfString<T> = T extends string ? { value: T } : T;

type A = WrapIfString<string>; // { value: string }
type B = WrapIfString<number>; // number

这说明条件类型的意义不是“炫技”,而是让类型能跟输入条件联动变化。

4. 常见用法二:过滤联合类型

type KeepString<T> = T extends string ? T : never;

type Result = KeepString<string | number | boolean>; // string

为什么能过滤?

因为联合类型会被逐个分支判断,最后把结果合并回来。

这也是 ExcludeExtract 这类工具类型的核心原理。

5. 常见用法三:配合 infer 提取类型

type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type R = GetReturnType<() => Promise<string>>; // Promise<string>

这里的 infer R 可以理解成:

  • 如果匹配到了某种函数结构;
  • 那就把它的返回值类型“推导出来”并命名为 R

这是高级类型题里非常高频的组合。

6. extends 在这里不是“继承”

这点经常混。

比如:

type X<T> = T extends string ? 1 : 2;

这里的 extends 更接近:

  • T 是否可以赋值给 string
  • T 是否满足某个约束条件。

它不是 class 之间那种运行时继承关系。

7. 怎么阻止联合类型分发

type ToArray<T> = T extends any ? T[] : never;
type A = ToArray<string | number>; // string[] | number[]

如果你想把联合当成整体判断,可以包一层:

type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type B = ToArrayNonDist<string | number>; // (string | number)[]

这一点是条件类型里的经典追问。

8. 高频面试题标准答法

8.1 extends 条件类型最常见的形式是什么

直接答:

type Xxx<T> = T extends U ? X : Y;

8.2 它和泛型约束里的 T extends U 是一回事吗

有关联,但语义位置不同:

  • function foo<T extends U>() {} 是泛型参数约束;
  • type R<T> = T extends U ? X : Y 是条件分支判断。

8.3 为什么很多工具类型都基于条件类型

因为它能做三件事:

  • 判断;
  • 过滤;
  • 提取。

这正是高级类型运算最需要的能力。

9. 常见误区

  • 误区 1:把这里的 extends 理解成类继承。
    • 条件类型里它更像“是否满足条件”。
  • 误区 2:看到联合类型分发就懵。
    • 记住“裸类型参数会逐个成员判断”。
  • 误区 3:只会背语法,不知道它能做什么。
    • 真正价值是构建可复用的类型工具。

速记要点

  • 条件类型语法:T extends U ? X : Y
  • 本质是在类型系统里写条件判断。
  • 常配合联合类型过滤和 infer 提取一起使用。