交叉类型满足以下特征:
- 唯一性:
A & A等价于A; - 满⾜交换律:
A & B等价于B & A; - 满⾜结合律:
(A & B) & C等价于A & (B & C); - ⽗类型收敛:如果 B 是 A 的⽗类型,则
A & B将被收敛成 A 类型:
type A0 = number & 1; // 1 其中 number 是 1 的父类型
type A1 = string & "1"; // "1"
type A2 = boolean & true; // true
type A3 = any & 1 // any
type A4 = any & boolean // any
type A5 = any & never // never
另外,除了 never类型交叉运算结果为 never类型外,任何类型和 any 类型交叉运算,结果都是 any 类型。
在多个对象类型做交叉运算的时候,如果存在相同属性,且属性类型为非基本数据类型,则可以进行合并。
type A1 = {
name: string;
age: number;
}
type A2 = {
location: string;
}
type A3 = A1 & A2;
/*
type A3 = {
name: string;
age: number;
location: string;
}
*/
若相同属性是可辨识的属性(即类型是字面量类型或者字面量类型组成的联合类型),则最后结果为 never类型。
type A = { kind: 'a', foo: string };
type B = { kind: 'b', foo: number };
type C = { kind: 'c', foo: number };
type AB = A & B; // never
type BC = B & C; // never
函数类型也支持交叉运算:
type F1 = (a: string, b: string) => void;
type F2 = (a: number, b: number) => void;
var f: F1 & F2 = (a: string | number, b: string | number) => { };
f("hello", "world"); // Ok
f(1, 2); // Ok
f(1, "test"); // Error
第三个报错是因为 TypeScript 编译器利用函数重载特性来实现不同函数类型的交叉运算。
可以再实现一个新的函数类型来解决该问题:
type F1 = (a: string, b: string) => void;
type F2 = (a: number, b: number) => void;
type F3 = (a: number, b: string) => void;
var f: F1 & F2 & F3 = (a: string | number, b: string | number) => { };
f("hello", "world"); // Ok
f(1, 2); // Ok
f(1, "test"); // Ok