Skip to content
On this page

高级类型

介绍

高级类型是 TypeScript 中的一组高级类型构造,它们允许创建更复杂和具有更高表现力的类型系统。您提到的 TypeScript 中最常用的一些高级类型包括:

  1. 交叉类型(Intersection Types):交叉类型允许您将多个类型合并为一个类型。例如,您可以创建一个类型,表示具有来自两种不同类型的属性的对象。

  2. 联合类型(Union Types):联合类型允许您定义一个可以包含多种类型值的类型。这在变量可以具有多个可能值的情况下非常有用。

  3. 类型别名(Type Aliases):类型别名允许您为任何数据类型创建自定义名称。这对于复杂类型或经常使用的类型非常方便。

  4. 条件类型(Conditional Types):条件类型用于创建依赖于其他类型的类型。它们允许您基于其他值的属性或类型有条件地定义类型。

  5. 索引类型(Index Types):索引类型允许您使用键访问对象的属性。这在您想要确保对象上存在某个键时非常有用。

  6. 映射类型(Mapped Types):映射类型是通过转换现有类型的属性来创建新类型的一种方式。它们通常用于使属性变成可选的、只读的或用于过滤属性。

  7. 类型守卫(Type Guards):类型守卫用于在条件块内缩小变量的类型范围。它们通常与 typeof 操作符或自定义函数一起使用。

通过明智地使用这些高级类型,您可以使 TypeScript 代码更易读、易维护,减少错误发生的可能性。它们提供了一种强大的方式来建模复杂的数据结构并在应用程序中强制执行类型安全性。

映射类型(Mapped Types)

在 TypeScript 中,映射类型(Mapped Types)是一种基于现有类型创建新类型的方式,其中现有类型的每个属性都以某种方式进行了转换。映射类型是通过使用 keyof 运算符和一种将现有类型的每个属性映射到新属性类型的类型来声明的。

例如,以下是一个映射类型,它接受一个对象类型并创建一个新类型,其中原始类型的所有属性的类型都被更改为只读:

typescript
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

let obj = { x: 10, y: 20 };
let readonlyObj: Readonly<typeof obj> = obj;

在这个例子中,Readonly 映射类型接受一个对象类型 T,并创建一个新类型,其中 T 的所有属性的类型都被更改为只读。keyof T 运算符用于提取 T 的属性名称,而 T[P] 语法用于访问 T 的每个属性的类型。readonly 关键字用于将新类型的属性设为只读。

通过映射类型,您可以在不重复定义属性名称的情况下,以类型安全的方式转换现有类型的属性。这使得代码更具可维护性,因为它允许您在需要时轻松更改属性的类型。

条件类型(Conditional Types)

在 TypeScript 中,条件类型(Conditional Types)是一种根据条件选择类型的方式。它们允许您编写一种类型,根据其输入的类型动态选择类型。条件类型是通过使用 infer 关键字和一个测试条件并根据测试结果选择类型的类型声明的。

例如,以下是一个条件类型,它接受两种类型并返回第一个参数的类型,如果它扩展第二个参数,否则返回第二个参数的类型:

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

type A = Extends<string, any>; // 类型 A 是 'string'
type B = Extends<any, string>; // 类型 B 是 'string'

在这个例子中,Extends 条件类型接受两种类型 TU,并返回第一个参数 T 的类型,如果它扩展第二个参数 U,则返回第二个参数 U 的类型。T extends U 的语法用于测试 T 是否扩展 U? T : U 的语法用于在测试通过时选择类型 T,否则选择类型 U

通过条件类型,您可以根据输入类型的不同情况来选择不同的类型,这使得您的类型定义更加灵活和具有动态性。这对于编写通用类型和处理各种情况非常有用。

字面类型(Literal Types)

在 TypeScript 中,字面类型(Literal Types)是一种精确指定值的方式,而不仅仅是类型。字面类型可用于强制值必须是特定类型和特定值。字面类型是通过使用字面值,如字符串、数字或布尔值,作为类型来创建的。

例如,以下是表示值为 42 的字面类型:

typescript
type Age = 42;

let age: Age = 42; // 正确
let age: Age = 43; // 错误

在这个例子中,Age 字面类型是通过使用数字 42 作为类型创建的。然后可以使用此类型来强制值必须是数字类型且具有值 42。

字面类型非常有用,因为它们允许您在类型中精确指定值,从而提高了类型的安全性和表达力。这在编写具有严格值要求的代码时非常有用。

模板字面类型(Template Literal Types)

在 TypeScript 中,模板字面类型(Template Literal Types)是一种操作字符串值作为类型的方式。它们允许您基于字符串操作或拼接的结果创建一种类型。模板字面类型是使用反引号(``)字符以及类型内的字符串操作表达式创建的。

例如,以下是一个将两个字符串拼接起来的模板字面类型:

typescript
type Name = `Mr. ${string}`;

let name: Name = `Mr. Smith`;  // 正确
let name: Name = `Mrs. Smith`;  // 错误

在这个例子中,Name 模板字面类型是通过将字符串 "Mr. " 与类型 string 进行拼接创建的。这个类型可以用来强制值必须是以 "Mr. " 开头的字符串。

模板字面类型非常有用,因为它们允许您根据字符串操作创建具有特定格式的类型,从而提高了代码的类型安全性。

递归类型(Recursive Types)

递归类型(Recursive Types)在 TypeScript 中是一种定义引用自身的类型的方式。递归类型用于定义复杂的数据结构,例如树形结构或链表,其中一个值可以包含一个或多个相同类型的值。

例如,以下是一个表示链表的递归类型:

typescript
type LinkedList<T> = {
  value: T;
  next: LinkedList<T> | null;
};

let list: LinkedList<number> = {
  value: 1,
  next: { value: 2, next: { value: 3, next: null } },
};

在这个例子中,LinkedList 类型被定义为一种类型,它扩展了类型 T,并包含了一个属性 next,其类型为 LinkedList<T>null。这允许我们创建一个链表,其中每个节点包含类型为 T 的值和对链表中下一个节点的引用。这是一种强大的方式来表示复杂的数据结构。