TS 中的类型运算:交叉类型

交叉类型(交集)

英文全称:intersection types

1
2
type A = string & number;
// ^-- never

交叉类型一般多用于对象,而不用于简单类型

1
2
3
4
5
6
type 有左手的人 = { left: string }

const b = { left: 'yse', right: 'yes' }
const a1: 有左手的人 = b // 不报错

const a2: 有左手的人 = { left: 'yse', right: 'yes' } // 报错

可用于接口求交集

1
2
3
4
5
6
7
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
type ColorfulCircle = Colorful & Circle;

可用于模拟继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Person = {
name: string;
age: number;
};
type User = Person & {
id: number;
email: string;
};
const u: User = {
id: 1,
name: 'ClariS',
age: 18,
email: 'xxx@yyy.com'
};

交叉类型的特殊情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Person = {
name: string;
age: number;
id: string;
};
type User = Person & {
id: number;
email: string;
};
const u: User = {
id: 1 as never, // 此处 id 的类型为 never
name: 'ClariS',
age: 18,
email: 'xxx@yyy.com',
};

当把上面 id 的类型从一个比较大的类型,变为比较小的类型时,整个 User 的类型都为 never

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Person = {
name: string;
age: number;
id: 'A';
};
type User = Person & {
id: 'B';
email: string;
};
const u: User = { // User = never
id: 1,
name: 'ClariS',
age: 18,
email: 'xxx@yyy.com',
};

type A = { kind: 'A'; name: string };
type B = { kind: 'B'; age: number } & A;
// ^-- never

上面的例子中,当对象属性发生冲突时,type 只会把类型变为 never,但类型并不报错,只在使用时报错;而 interface 会直接报错

1
2
3
4
5
6
7
8
9
10
interface Person {
name: string;
age: number;
id: string;
}
interface User extends Person {
// ^-- Type 'number' is not assignable to type 'string'
id: number;
email: string;
}

函数的交集会得到一个参数的并集

1
2
3
4
5
6
7
8
9
10
11
12
type A = {
method: (a: number) => void;
};
type B = {
method: (a: string) => void;
} & A;

const b: B = {
method(a) {
a; // number | string
}
};

总结:交叉类型常用于有交集的类型 A、B,如果 A、B 无交集,可能得到 never,也可能只是属性为 never


(●'◡'●)ノ♥