TypeScript 条件类型:简单类型检查

TypeScript 的类型系统远不止于标注变量类型。条件类型(Conditional Types)是其最强大的特性之一,它允许你基于类型关系动态推导新类型,实现类型层面的逻辑分支,极大提升了类型表达的灵活性与精确性。

核心语法:T extends U ? X : Y

  • 基础逻辑: 如果类型 T 能赋值给类型 U(即满足约束 U),则此条件类型的结果是 X,否则是 Y
  • 类型层面的 if 语句: 这本质上是类型空间的条件判断,在编译时进行计算。

为何强大?动态类型推导

条件类型的核心价值在于根据输入类型动态决定输出类型。例如,内置工具类型 Exclude<T, U> 的实现原理:

type Exclude<T, U> = T extends U ? never : T;
 
 
  • 它遍历 T (联合类型) 中的每个成员。
  • 如果某个成员能赋值给 U,则将其排除(结果为 never)。
  • 否则,保留该成员。
  • type Result = Exclude<'a' | 'b' | 'c', 'a' | 'b'>; // 'c'

关键特性:分布式条件类型

当条件类型作用于联合类型 (T 是联合类型如 A | B | C) 时,它会自动分发到联合类型的每个成员上:

type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>; // string[] | number[]
 
 
  • 结果不是 (string | number)[],而是 string[] | number[]
  • 这是处理联合类型时极其重要的行为模式。

infer 关键字:类型模式匹配

条件类型结合 infer 可以提取类型结构中的部分信息,如同解构:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
 
 
  • infer R 声明了一个待推断的类型变量 R
  • 如果 T 是函数类型,则匹配其返回类型并赋值给 R,最终 ReturnType<T> 就是 R
  • 否则,结果为 any

实战应用示例:Flatten

type Flatten<T> = T extends Array<infer Item> ? Item : T;
type Nested = number[][];
type Flat = Flatten<Nested>; // number[]
 
 
  • 检查 T 是否是数组类型。
  • 如果是,用 infer Item 提取其元素类型 Item,结果类型就是 Item
  • 如果不是,直接返回 T 本身。

最佳实践与注意点

  1. 优先内置工具: 许多实用条件类型(ExcludeExtractNonNullableReturnTypeParameters 等)已内置在 TS 中,优先使用。
  2. 理解分发: 牢记联合类型在条件类型中的分发行为,这是核心也是常见困惑点。用 [T] extends [U] 的形式可以禁用分发
  3. infer 威力: 结合条件使用 infer 是构建复杂、灵活类型工具(如推导函数参数、Promise 解包等)的基石。
  4. 避免过度复杂: 虽然强大,但过度嵌套的条件类型会降低代码可读性。保持适度,必要时添加注释。
posted @ 2025-10-19 12:12  alloutlove  阅读(7)  评论(0)    收藏  举报