TypeScript交叉类型:让类型组合更灵活
在写前端项目的时候,经常会遇到这样一种情况:一个对象既要具备用户信息,又要包含操作权限。比如你正在做一个后台管理系统,用户登录后,页面要显示他的基本信息,同时还要判断他有没有删除数据的权限。这时候如果用 TypeScript,该怎么定义这种“既是A又是B”的类型?答案就是——交叉类型。
交叉类型(Intersection Type)允许你把多个类型合并成一个,新类型拥有所有组成部分的特性。它的符号是 &,读作“和”,意思是“这个值必须同时满足这些类型”。
怎么用交叉类型?
举个例子。假设你有两个接口,一个描述用户的基本信息,另一个描述角色权限:
interface User {
name: string;
age: number;
}
interface AdminRole {
hasDeletePermission: boolean;
role: string;
}现在你要定义一个管理员用户,他既有用户信息,又有管理权限。这时候就可以用交叉类型:
type AdminUser = User & AdminRole;这样一来,AdminUser 就必须同时包含 name、age、hasDeletePermission 和 role 这四个字段。
实际使用时,就像这样:
const admin: AdminUser = {
name: "张三",
age: 30,
hasDeletePermission: true,
role: "admin"
};如果漏了任何一个字段,TypeScript 编译器就会报错,帮你提前发现问题。
交叉类型还能处理函数和联合类型
不止对象可以交叉,函数也能用。比如你有两个函数类型,一个返回字符串,一个返回数字:
type StringFn = () => string;
type NumberFn = () => number;
type CombinedFn = StringFn & NumberFn;虽然这个例子看起来有点奇怪——一个函数不可能同时只返回字符串又只返回数字——但在一些高级类型编程中,这种写法会出现在重载或泛型场景里,帮助类型系统更精确地推导。
另外,交叉类型和联合类型(|)经常一起出现。比如你有一个配置对象,某些字段可能是多种类型之一,但整体结构又要合并:
interface Logger {
log: (msg: string) => void;
}
interface Saver {
save: (data: string | number) => boolean;
}
type LoggerSaver = Logger & Saver;这个 LoggerSaver 类型就既能打印日志,又能保存数据,适合用在需要同时记录和存储的模块中。
在日常开发中,交叉类型最常出现在封装组件或设计工具函数时。比如你写了一个 React 组件,既想接收通用的 props,又想额外加一些特定功能的配置,用交叉类型就很自然。
它不像继承那样有父子关系,而是平等地“拼接”多个类型,逻辑更清晰,也更容易维护。
掌握交叉类型,能让你在 TypeScript 中更自由地组合类型,写出既安全又灵活的代码。下次当你发现一个对象“又是这个,又是那个”的时候,别忘了试试 & 操作符。