跳到主要内容

TypeScript 条件类型

介绍

TypeScript 的条件类型(Conditional Types)是一种强大的工具,它允许我们根据类型之间的关系动态选择类型。条件类型的语法类似于 JavaScript 中的三元运算符,但它作用于类型层面。通过条件类型,我们可以编写更加灵活和可重用的类型定义。

条件类型的基本语法如下:

typescript
T extends U ? X : Y

其中:

  • T 是一个类型。
  • U 是另一个类型。
  • 如果 T 可以赋值给 U,则条件类型的结果为 X,否则为 Y

基本用法

让我们从一个简单的例子开始,了解条件类型的基本用法。

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

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

在这个例子中,IsString 是一个条件类型,它检查 T 是否是 string 类型。如果是,则返回 true,否则返回 false

条件类型与泛型

条件类型通常与泛型结合使用,以便在更复杂的场景中动态选择类型。例如,我们可以创建一个类型,根据输入类型的不同返回不同的类型。

typescript
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: "object";

type A = TypeName<string>; // "string"
type B = TypeName<number>; // "number"
type C = TypeName<boolean>; // "boolean"
type D = TypeName<object>; // "object"

在这个例子中,TypeName 类型根据 T 的类型返回不同的字符串字面量类型。

分布式条件类型

当条件类型作用于联合类型时,TypeScript 会将条件类型“分发”到联合类型的每个成员上。这种行为称为分布式条件类型。

typescript
type ToArray<T> = T extends any ? T[] : never;

type A = ToArray<string | number>; // string[] | number[]

在这个例子中,ToArray 类型将联合类型 string | number 转换为 string[] | number[]

提示

分布式条件类型只在 T 是裸类型参数(即没有包裹在数组、元组等结构中)时生效。

实际应用场景

条件类型在实际开发中有许多应用场景。以下是一些常见的例子:

1. 过滤联合类型

我们可以使用条件类型从联合类型中过滤出特定的类型。

typescript
type Filter<T, U> = T extends U ? T : never;

type A = Filter<string | number | boolean, string | boolean>; // string | boolean

在这个例子中,Filter 类型从 string | number | boolean 中过滤出 string | boolean

2. 提取函数返回类型

我们可以使用条件类型提取函数的返回类型。

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

function foo() {
return 42;
}

type A = ReturnType<typeof foo>; // number

在这个例子中,ReturnType 类型提取了函数 foo 的返回类型 number

3. 递归条件类型

条件类型可以递归地应用于自身,以处理更复杂的类型转换。

typescript
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

type A = DeepReadonly<{ a: number; b: { c: string } }>;
// { readonly a: number; readonly b: { readonly c: string } }

在这个例子中,DeepReadonly 类型递归地将对象的所有属性设置为只读。

总结

TypeScript 的条件类型为我们提供了一种强大的工具,可以根据类型之间的关系动态选择类型。通过条件类型,我们可以编写更加灵活和可重用的类型定义,从而提升代码的可维护性和可读性。

在实际开发中,条件类型可以用于过滤联合类型、提取函数返回类型、递归地处理复杂类型等场景。掌握条件类型的使用,将有助于你编写更加高效和健壮的 TypeScript 代码。

附加资源

练习

  1. 创建一个条件类型 IsArray<T>,检查 T 是否是数组类型。
  2. 使用条件类型实现一个 NonNullable<T> 类型,从 T 中移除 nullundefined
  3. 创建一个递归条件类型 Flatten<T>,将嵌套数组类型扁平化。

通过完成这些练习,你将进一步巩固对条件类型的理解。