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