TypeScript 交叉类型
交叉类型用 & 把多个类型合并成一个"同时具备各方全部成员"的新类型。它擅长把分散的小接口拼成完整对象,也能用于给函数附加属性、与泛型组合,是类型体操中最常用的积木之一。
基本语法
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
// ColorfulCircle 同时拥有 color 与 radius
type ColorfulCircle = Colorful & Circle;
const cc: ColorfulCircle = { color: "red", radius: 5 };
console.log(cc.color, cc.radius); // 输出:red 5
注意与联合类型区分:A | B 表示"是 A 或 B",A & B 表示"既是 A 又是 B"。
同名属性的合并细节
当交叉的两个类型都定义了同名属性时,该属性的类型取两者的交集:
type A = { id: number; tag: string };
type B = { id: number; level: 1 | 2 | 3 };
type C = A & B; // id: number,level: 1 | 2 | 3
const obj: C = { id: 7, tag: "x", level: 2 }; // 合法
console.log(obj); // 输出:{ id: 7, tag: 'x', level: 2 }
若同名属性类型互不兼容,结果会退化成 never,实际上无法构造出合法值:
type X = { id: string };
type Y = { id: number };
type Z = X & Y; // id 为 string & number = never
给函数类型附加属性
交叉类型可以描述"可调用对象",例如带版本号的函数:
type Greeter = ((name: string) => string) & { version: string };
const greet = ((name: string) => `你好,${name}`) as Greeter;
greet.version = "1.0.0";
console.log(greet("张三")); // 输出:你好,张三
console.log(greet.version); // 输出:1.0.0
与泛型组合
交叉类型配合泛型,可写出"给任意类型附加 id"这类通用工具:
type WithId<T> = T & { id: number };
function toRecord<T>(item: T, id: number): WithId<T> {
return { ...item, id };
}
const user = toRecord({ name: "李四", age: 20 }, 1);
console.log(user); // 输出:{ name: '李四', age: 20, id: 1 }
console.log(user.name, user.id); // 输出:李四 1
小结
交叉类型表达"合并":对象型数据用 & 拼接成员,函数型数据用 & 附加静态属性。写类型工具时把它与泛型、keyof 搭配,就能拼出许多复杂的场景类型。