写前端代码时,经常会遇到需要把多个ref="/tag/241/" style="color:#479099;font-weight:bold;">对象的属性合并在一起的情况。比如做网络监控功能时,一个设备可能既有基础信息,又有状态数据。这时候用 TypeScript 的交叉类型,能让类型定义变得更清晰、更安全。
什么是交叉类型
交叉类型其实就是把多个类型“合并”成一个新类型。语法是用 & 符号连接。合并后的类型拥有所有组成部分的属性。
比如有两个类型,一个描述设备基本信息,另一个描述当前状态:
interface DeviceInfo {
id: string;
name: string;
}
interface DeviceStatus {
online: boolean;
lastPing: number;
}
type FullDevice = DeviceInfo & DeviceStatus;
这样一来,FullDevice 就同时包含 id、name、online 和 lastPing 四个字段。如果少写任何一个,在编译时就会报错。
实际场景中的用法
假设你在做一个网络监控面板,要从不同接口获取数据。一部分来自设备注册服务,另一部分来自心跳上报系统。你可以分别定义类型,再用交叉类型组合。
interface BasicInfo {
deviceId: string;
location: string;
}
interface HealthData {
cpuUsage: number;
memoryUsage: number;
timestamp: number;
}
const device: BasicInfo & HealthData = {
deviceId: 'dev-001',
location: '机房A',
cpuUsage: 0.75,
memoryUsage: 0.68,
timestamp: Date.now()
};
这样写不仅结构清晰,还能避免手动拼接类型出错。IDE 也能准确提示所有可用字段,减少运行时 bug。
和接口继承比有什么不同
你可能会想,为什么不直接用 extends?交叉类型的优势在于它更灵活,可以随时组合,不需要一开始就设计好继承关系。尤其是在处理第三方库或动态数据时,临时合并类型特别方便。
而且交叉类型支持任意数量的组合,甚至可以混用接口、类型别名、字面量类型:
type TemporaryDevice = DeviceInfo & { tempId: number } & Partial<HealthData>;
上面这个类型表示:必须有 DeviceInfo 的所有字段,加上一个数字型的 tempId,而健康数据则是可选的。
注意属性冲突的情况
如果两个类型有同名属性但类型不一致,交叉后该属性会变成 never。比如一个是 string,另一个是 number,那就没法共存。
interface A { x: string }
interface B { x: number }
type Conflicted = A & B; // x 的类型是 never
这种情况在项目中容易引发问题,尤其是对接多个接口时字段命名冲突。建议提前统一命名规范,或者用映射类型做转换。