换个视角来看TypeScript中的交叉运算

引文

相信只要接触过ts的同学就有了解交叉类型这两个概念,以前我对交叉类型感到非常疑惑,明明叫交叉类型,为何对对象类型使用了交叉运算后类型反而会进行属性的合并?不知道大家有没有和我一样的困惑。这篇文章我会分享我最近感悟到的用不同视角来解释出现上述问题的原因,如有错误,恳请指正。

交叉运算

在ts中,使用&这个符号来对两个类型进行交叉运算,下面举几个小例子来开始讲解。

例一

type A = number & string // never

例二

type A = 1 & number // 1
type B = "hello" & string // "hello"

例三

type A1 = {a: number}
type A2 = {aa: string}

这里的例子正是我在引文中提到的情况,按照交叉这个字面意思来理解,{a: number}{aa: string}两个好像也没有什么交集,按照例一的思路来思考,结果应该是never,为何结果是{a: number, aa: string}

首先来思考一个问题,假设有这么几个对象:

  • {a: 1, b: 2}
  • {aa: "11", bb: "22"}
  • {a: 1, b: 2, aa: "11", bb: "22"}

这几个对象分别赋值给类型为A1、A2、A的变量,哪个类型的变量在被赋值的时候有比较大的可能会出现错误?

相信大家能够很容易的猜到答案,那就是上面的这三个对象在给类型为A的变量赋值的时候前两个对象都会报错,只有最后一个对象是符合类型要求的。

上述中的A1、A2类型,A1类型的变量只需要值中有属性名为a,属性值类型为number的属性即可满足,而A2类型的变量只需要值中有属性名为aa,属性值类型为string的属性即可满足,而A类型的变量对值的要求是必须要同时有a和aa这两个属性。

那么符合A1、A2、A类型的值各有几个?可以归类下

  • 符合A1类型的值:{a: 1, b: 2}、{a: 1, b: 2, aa: "11", bb: "22"}
  • 符合A2类型的值:{aa: "11", bb: "22"}、{a: 1, b: 2, aa: "11", bb: "22"}
  • 符合A类型的值:{a: 1, b: 2, aa: "11", bb: "22"}

可以看到在A1 & A2后得到的A类型,其值相对于A1和A2这两个类型对应的值的范围是变小的,这也符合交叉运算的结果趋势。

我们对数学中的交并集运算有着很深的印象,但是数学上交并集运算作用的对象却是具体的数值,如果把这种思想转换到ts类型上来,其实不太合适,而是应该把这种思想作用到ts类型所对应的值上。

现在用这种思路去思考例一和例二,也是能够走通的。

交叉运算在处理对象类型的时候,交叉过后属性反而增多,初看觉得不对劲,但转换角度细想或许能发现其中的道理。

总结:交叉运算会导致能够赋值给结果类型的变量范围变小,这个类型的限制也会变得更严格。

作者:Qing原文地址:https://segmentfault.com/a/1190000043495173

%s 个评论

要回复文章请先登录注册