交叉类型 (Intersection Types)
交叉类型是 TypeScript 中的一种强大特性,它允许你组合多个类型的属性和方法,创建一个新类型。这个新类型包含所有参与交叉的类型的成员。换句话说,如果你有两个或更多的类型,并且希望创建一个同时具有这些类型所有特性的类型,那么你可以使用交叉类型。
定义交叉类型
你可以使用 & 操作符来定义交叉类型。下面是一些基本的例子:
// 定义两个接口
interface Bird {
fly: () => void;
}
interface Fish {
swim: () => void;
}
// 使用 & 创建交叉类型
type FlyingFish = Bird & Fish;
// 实现交叉类型
const flyingFish: FlyingFish = {
fly() {
console.log("Flying...");
},
swim() {
console.log("Swimming...");
},
};在这个例子中,FlyingFish 类型既包含了 Bird 接口的所有成员(即 fly 方法),也包含了 Fish 接口的所有成员(即 swim 方法)。因此,任何实现 FlyingFish 类型的对象都必须提供这两个方法。
交叉类型的属性访问
当处理交叉类型时,TypeScript 允许你访问所有被交叉类型的属性和方法,因为它们都被认为是该交叉类型的一部分。
flyingFish.fly(); // 输出: Flying...
flyingFish.swim(); // 输出: Swimming...交叉类型与联合类型的对比
联合类型 (
|):表示一个值可以是几种类型中的任意一种。typescripttype Pet = Bird | Fish;交叉类型 (
&):表示一个值必须同时满足几种类型的条件。typescripttype FlyingFish = Bird & Fish;
交叉类型的常见用法
扩展对象形状:你可以使用交叉类型来扩展已有类型的功能,而无需修改原始类型定义。
typescriptinterface Square { width: number; } interface Rectangle extends Square { height: number; } // 或者使用交叉类型 type ColoredSquare = Square & { color: string }; const coloredSquare: ColoredSquare = { width: 10, color: "red", };混入(Mixins):在面向对象编程中,混入是一种将多个类的行为组合到一起的技术。虽然 TypeScript 不直接支持多继承,但你可以通过交叉类型模拟混入。
typescriptclass Movable { move() { console.log("Moving..."); } } class Resizable { resize() { console.log("Resizing..."); } } // 使用交叉类型模拟混入 type MovableResizable = Movable & Resizable; function createMovableResizable(): MovableResizable { return { move: () => console.log("Moving..."), resize: () => console.log("Resizing..."), }; } const obj = createMovableResizable(); obj.move(); obj.resize();函数重载:交叉类型还可以用来描述函数签名之间的交集。
typescriptfunction padLeft(value: string, padding: string): string; function padLeft(value: string, padding: number): string; function padLeft(value: string, padding: string | number): string { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value; } return padding + value; } // 使用交叉类型简化函数重载 type PadFunction = ((value: string, padding: string) => string) & ((value: string, padding: number) => string); const pad: PadFunction = padLeft;实用工具类型:交叉类型经常出现在 TypeScript 的内置实用工具类型中,如
Partial<T>、Readonly<T>等等。typescripttype PartialPerson = Partial<{ name: string; age: number }>;
注意事项
重复属性冲突:如果两个类型中有同名但不兼容的属性,TypeScript 编译器会报错。例如:
typescriptinterface A { x: number; } interface B { x: string; } type AB = A & B; // 错误:Property 'x' has conflicting types in types 'A' and 'B'.可选属性:如果两个类型都有同名的可选属性,则交叉类型的结果也将是可选的。
typescriptinterface A { x?: number; } interface B { x?: string; } type AB = A & B; // x 是可选的,并且是 number | string 类型
总结
交叉类型是 TypeScript 提供的一个强大工具,它允许你组合多个类型的属性和方法,创建一个新类型。理解交叉类型的工作原理及其与联合类型的区别,可以帮助你在编写代码时充分利用 TypeScript 的灵活性,同时保持良好的类型安全性。