交叉类型(Intersection Types)(交集)
type A = string & number
很显然 A 的结果是 never,因为字符串和数字是两种完全不同的东西,所以一般交叉类型,我们不会用在普通类上
type 有左手的人 = {
left: string;
}
type 有右手的人 = {
right: string;
}
type C = 有左手的人 | 有右手的人
type D = 有左手的人 & 有右手的人
以上的 C、D 类型用一张图表示:
思考"有左手的人" 可以有"右手"吗?
type 有左手的人 = {
left: string;
}
const a: 有左手的人 = {
left: '左手',
right: '右手', // TODO: 这里会有报错
}
很显然,这里的代码报错了,但是从逻辑上来讲,"有左手的人" 难道不能有"右手"吗?,再来看接下来的栗子:
type 有左手的人 = {
left: string;
}
const b = {
left: '左手',
right: '右手',
}
const a: 有左手的人 = b
神奇的是,竟然不报错了,这就是 ts 很奇怪的地方,初始化的时候不能有多余的东西
接口也能交集
interface 有左手的人 {
left: string;
}
interface 有右手的人 {
right: string;
}
type 完整的手 = 有左手的人 & 有右手的人
特殊情况
普通对象
type Person = {
name: string;
age: number;
id: string;
}
type User = Person & {
id : number; // TODO: 注意:这里并没有报错
email: string;
}
const a: User = {
id: 1, // TODO: 这里报错了,并且提示类型为 never,
name: 'Jack',
email: 'qq.com',
}
但是稍微改造一点,还有更特殊的情况
type Person = {
name: string;
age: number;
id: 'A'; // TODO: 这里更具体了
}
type User = Person & {
id : 'B'; // TODO: 这里更具体了
email: string;
}
const a: User = { // TODO: 这里直接提示 User 类型为 never,
id: 1,
name: 'Jack',
email: 'qq.com',
}
这就很难解释了,直接记住这种情况把~
函数
type A = {
method: (n: number) => void
}
type B = {
method: (n: string) => void
}
const b: B = {
method: n => { // TODO: 没有报错
console.log(n)
}
}
可以发现当为函数的时候这里没有报错,且参数 n 的类型为 string | number,
一个接受参数类型为 number 的方法,一个接受参数类型为 string 的方法,这两个方法有没有交集呢?到目前来看已经很难想清楚了,明明是交集,怎么会得出并集!我们再来验证一下:
type F1 = (n: number) => void
type F2 = (n: string) => void
type X = F1 & F2
const x: X = (n) => {
console.log(n)
}
也没有报错,且参数 n 的类型为 string | number
也就是说,如果我们再在做两个对象交集的时候,遇到 key 的名字冲突的时候,那么他会对这个属性进行交集,且递归的交。
但是特殊在函数这里,函数的交集,会得到参数的并集,说实话我又不是很理解了,没办法按实践的结果来死记硬背把~