一、概述
联合类型(Union Types)是 TypeScript 中的一种高级类型,允许你将多个类型组合在一起,表示可以是这些类型中的任意一种。联合类型在处理多种可能类型的变量时非常有用。本文将详细介绍联合类型的各种应用场景,并通过示例代码说明每个概念的使用方法。
二、什么是联合类型
联合类型使用 |
符号将多个类型组合在一起。例如,string | number
表示可以是 string
类型或 number
类型。
示例
let value: string | number;
value = "Hello"; // 合法
value = 42; // 合法
在上面的例子中,变量 value
可以是字符串或数字。
使用场景
- 多类型变量:当一个变量可以是多种类型时,如函数参数或返回值可以有多种可能类型。
- 灵活处理输入:当需要处理多种类型的输入时,如函数可以接受多种类型的参数。
function formatValue(value: string | number): string {
if (typeof value === "string") {
return `String: ${value}`;
} else {
return `Number: ${value}`;
}
}
console.log(formatValue("Hello")); // String: Hello
console.log(formatValue(123)); // Number: 123
三、联合类型与类型保护
类型保护(Type Guards)是 TypeScript 提供的一种机制,允许你在运行时检查类型并进行相应的类型转换。类型保护常用于联合类型,确保你可以安全地操作变量。
示例
function printLength(value: string | number): void {
if (typeof value === "string") {
console.log(value.length); // 处理字符串
} else {
console.log(value.toFixed(2)); // 处理数字
}
}
printLength("Hello"); // 5
printLength(42.123); // 42.12
在上面的例子中,通过 typeof
操作符进行类型检查,根据不同的类型执行不同的操作。
使用场景
- 安全类型操作:当需要根据变量的实际类型进行不同操作时,如根据类型调用不同的方法。
- 提高代码可读性:通过类型保护使代码更清晰,避免类型错误。
function getValueLength(value: string | any[]): number {
if (typeof value === "string") {
return value.length;
} else if (Array.isArray(value)) {
return value.length;
} else {
return 0;
}
}
console.log(getValueLength("Hello")); // 5
console.log(getValueLength([1, 2, 3])); // 3
console.log(getValueLength(123)); // 0
四、联合类型与接口
联合类型可以与接口结合使用,创建更加灵活和复杂的类型结构。你可以使用接口定义多个类型,然后通过联合类型将它们组合在一起。
示例
interface Cat {
meow: () => void;
}
interface Dog {
bark: () => void;
}
type Pet = Cat | Dog;
function makeSound(pet: Pet): void {
if ("meow" in pet) {
pet.meow();
} else {
pet.bark();
}
}
const myCat: Cat = { meow: () => console.log("Meow") };
const myDog: Dog = { bark: () => console.log("Woof") };
makeSound(myCat); // Meow
makeSound(myDog); // Woof
在上面的例子中,通过联合类型 Pet
,makeSound
函数可以接受 Cat
或 Dog
类型的参数。
使用场景
- 多态操作:当函数需要处理多种类型的参数时,如根据不同类型参数调用不同的方法。
- 类型组合:当需要将多个类型组合在一起创建新的类型时,如不同接口类型的组合。
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "square":
return shape.size * shape.size;
case "rectangle":
return shape.width * shape.height;
case "circle":
return Math.PI * shape.radius * shape.radius;
default:
return 0;
}
}
const square: Square = { kind: "square", size: 10 };
const rectangle: Rectangle = { kind: "rectangle", width: 5, height: 20 };
const circle: Circle = { kind: "circle", radius: 7 };
console.log(getArea(square)); // 100
console.log(getArea(rectangle)); // 100
console.log(getArea(circle)); // 153.93804002589985
五、联合类型与字面量类型
字面量类型(Literal Types)允许你使用具体的值作为类型。联合字面量类型可以表示一组具体的值,使得类型更加精确。
示例
type Direction = "up" | "down" | "left" | "right";
function move(direction: Direction): void {
console.log(`Moving ${direction}`);
}
move("up"); // Moving up
move("down"); // Moving down
在上面的例子中,Direction
类型只能是 "up"
、"down"
、"left"
或 "right"
之一。
使用场景
- 限定值范围:当变量只能是某些特定值时,如函数参数只能是指定的一组值。
- 提高类型安全:通过字面量类型限制值的范围,避免传入无效值。
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
function request(url: string, method: HTTPMethod): void {
console.log(`Requesting ${url} with method ${method}`);
}
request("/api/resource", "GET"); // Requesting /api/resource with method GET
request("/api/resource", "POST"); // Requesting /api/resource with method POST
六、联合类型与可选属性
联合类型可以与可选属性结合使用,使得类型定义更加灵活。可选属性在类型定义中使用 ?
表示,表示该属性是可选的。
示例
interface OptionalProperties {
name?: string;
age?: number;
}
let person1: OptionalProperties = { name: "Alice" };
let person2: OptionalProperties = { age: 30 };
let person3: OptionalProperties = { name: "Bob", age: 25 };
在上面的例子中,OptionalProperties
接口定义了两个可选属性 name
和 age
,这使得对象可以有也可以没有这些属性。
使用场景
- 灵活的数据结构:当对象的某些属性是可选时,如表单输入的部分字段可以为空。
- 兼容性处理:当需要处理不同形态的对象时,如处理旧版本对象的兼容性。
interface Config {
url: string;
method?: "GET" | "POST";
timeout?: number;
}
function createRequest(config: Config): void {
let method = config.method || "GET";
let timeout = config.timeout || 3000;
console.log(`Requesting ${config.url} with method ${method} and timeout ${timeout}`);
}
createRequest({ url: "/api/data" }); // Requesting /api/data with method GET and timeout 3000
createRequest({ url: "/api/data", method: "POST" }); // Requesting /api/data with method POST and timeout 3000
结论
联合类型是 TypeScript 中的重要特性,提供了灵活且强大的类型定义方式。通过掌握联合类型与类型保护、接口、字面量类型和可选属性的结合使用,你可以编写出更具通用性和可重用性的代码。在实际开发中,合理使用联合类型可以提高代码的类型安全性和可读性,帮助你更好地处理复杂的数据结构和类型操作。希望这篇文章能够帮助你更好地理解和使用 TypeScript 的联合类型。