一、概述

联合类型(Union Types)是 TypeScript 中的一种高级类型,允许你将多个类型组合在一起,表示可以是这些类型中的任意一种。联合类型在处理多种可能类型的变量时非常有用。本文将详细介绍联合类型的各种应用场景,并通过示例代码说明每个概念的使用方法。

二、什么是联合类型

联合类型使用 | 符号将多个类型组合在一起。例如,string | number 表示可以是 string 类型或 number 类型。

示例

  1. let value: string | number;
  2. value = "Hello"; // 合法
  3. value = 42; // 合法

在上面的例子中,变量 value 可以是字符串或数字。

使用场景

  • 多类型变量:当一个变量可以是多种类型时,如函数参数或返回值可以有多种可能类型。
  • 灵活处理输入:当需要处理多种类型的输入时,如函数可以接受多种类型的参数。
  1. function formatValue(value: string | number): string {
  2. if (typeof value === "string") {
  3. return `String: ${value}`;
  4. } else {
  5. return `Number: ${value}`;
  6. }
  7. }
  8. console.log(formatValue("Hello")); // String: Hello
  9. console.log(formatValue(123)); // Number: 123

三、联合类型与类型保护

类型保护(Type Guards)是 TypeScript 提供的一种机制,允许你在运行时检查类型并进行相应的类型转换。类型保护常用于联合类型,确保你可以安全地操作变量。

示例

  1. function printLength(value: string | number): void {
  2. if (typeof value === "string") {
  3. console.log(value.length); // 处理字符串
  4. } else {
  5. console.log(value.toFixed(2)); // 处理数字
  6. }
  7. }
  8. printLength("Hello"); // 5
  9. printLength(42.123); // 42.12

在上面的例子中,通过 typeof 操作符进行类型检查,根据不同的类型执行不同的操作。

使用场景

  • 安全类型操作:当需要根据变量的实际类型进行不同操作时,如根据类型调用不同的方法。
  • 提高代码可读性:通过类型保护使代码更清晰,避免类型错误。
  1. function getValueLength(value: string | any[]): number {
  2. if (typeof value === "string") {
  3. return value.length;
  4. } else if (Array.isArray(value)) {
  5. return value.length;
  6. } else {
  7. return 0;
  8. }
  9. }
  10. console.log(getValueLength("Hello")); // 5
  11. console.log(getValueLength([1, 2, 3])); // 3
  12. console.log(getValueLength(123)); // 0

四、联合类型与接口

联合类型可以与接口结合使用,创建更加灵活和复杂的类型结构。你可以使用接口定义多个类型,然后通过联合类型将它们组合在一起。

示例

  1. interface Cat {
  2. meow: () => void;
  3. }
  4. interface Dog {
  5. bark: () => void;
  6. }
  7. type Pet = Cat | Dog;
  8. function makeSound(pet: Pet): void {
  9. if ("meow" in pet) {
  10. pet.meow();
  11. } else {
  12. pet.bark();
  13. }
  14. }
  15. const myCat: Cat = { meow: () => console.log("Meow") };
  16. const myDog: Dog = { bark: () => console.log("Woof") };
  17. makeSound(myCat); // Meow
  18. makeSound(myDog); // Woof

在上面的例子中,通过联合类型 PetmakeSound 函数可以接受 CatDog 类型的参数。

使用场景

  • 多态操作:当函数需要处理多种类型的参数时,如根据不同类型参数调用不同的方法。
  • 类型组合:当需要将多个类型组合在一起创建新的类型时,如不同接口类型的组合。
  1. interface Square {
  2. kind: "square";
  3. size: number;
  4. }
  5. interface Rectangle {
  6. kind: "rectangle";
  7. width: number;
  8. height: number;
  9. }
  10. interface Circle {
  11. kind: "circle";
  12. radius: number;
  13. }
  14. type Shape = Square | Rectangle | Circle;
  15. function getArea(shape: Shape): number {
  16. switch (shape.kind) {
  17. case "square":
  18. return shape.size * shape.size;
  19. case "rectangle":
  20. return shape.width * shape.height;
  21. case "circle":
  22. return Math.PI * shape.radius * shape.radius;
  23. default:
  24. return 0;
  25. }
  26. }
  27. const square: Square = { kind: "square", size: 10 };
  28. const rectangle: Rectangle = { kind: "rectangle", width: 5, height: 20 };
  29. const circle: Circle = { kind: "circle", radius: 7 };
  30. console.log(getArea(square)); // 100
  31. console.log(getArea(rectangle)); // 100
  32. console.log(getArea(circle)); // 153.93804002589985

五、联合类型与字面量类型

字面量类型(Literal Types)允许你使用具体的值作为类型。联合字面量类型可以表示一组具体的值,使得类型更加精确。

示例

  1. type Direction = "up" | "down" | "left" | "right";
  2. function move(direction: Direction): void {
  3. console.log(`Moving ${direction}`);
  4. }
  5. move("up"); // Moving up
  6. move("down"); // Moving down

在上面的例子中,Direction 类型只能是 "up""down""left""right" 之一。

使用场景

  • 限定值范围:当变量只能是某些特定值时,如函数参数只能是指定的一组值。
  • 提高类型安全:通过字面量类型限制值的范围,避免传入无效值。
  1. type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
  2. function request(url: string, method: HTTPMethod): void {
  3. console.log(`Requesting ${url} with method ${method}`);
  4. }
  5. request("/api/resource", "GET"); // Requesting /api/resource with method GET
  6. request("/api/resource", "POST"); // Requesting /api/resource with method POST

六、联合类型与可选属性

联合类型可以与可选属性结合使用,使得类型定义更加灵活。可选属性在类型定义中使用 ? 表示,表示该属性是可选的。

示例

  1. interface OptionalProperties {
  2. name?: string;
  3. age?: number;
  4. }
  5. let person1: OptionalProperties = { name: "Alice" };
  6. let person2: OptionalProperties = { age: 30 };
  7. let person3: OptionalProperties = { name: "Bob", age: 25 };

在上面的例子中,OptionalProperties 接口定义了两个可选属性 nameage,这使得对象可以有也可以没有这些属性。

使用场景

  • 灵活的数据结构:当对象的某些属性是可选时,如表单输入的部分字段可以为空。
  • 兼容性处理:当需要处理不同形态的对象时,如处理旧版本对象的兼容性。
  1. interface Config {
  2. url: string;
  3. method?: "GET" | "POST";
  4. timeout?: number;
  5. }
  6. function createRequest(config: Config): void {
  7. let method = config.method || "GET";
  8. let timeout = config.timeout || 3000;
  9. console.log(`Requesting ${config.url} with method ${method} and timeout ${timeout}`);
  10. }
  11. createRequest({ url: "/api/data" }); // Requesting /api/data with method GET and timeout 3000
  12. createRequest({ url: "/api/data", method: "POST" }); // Requesting /api/data with method POST and timeout 3000

结论

联合类型是 TypeScript 中的重要特性,提供了灵活且强大的类型定义方式。通过掌握联合类型与类型保护、接口、字面量类型和可选属性的结合使用,你可以编写出更具通用性和可重用性的代码。在实际开发中,合理使用联合类型可以提高代码的类型安全性和可读性,帮助你更好地处理复杂的数据结构和类型操作。希望这篇文章能够帮助你更好地理解和使用 TypeScript 的联合类型。