最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 理解Ts联合类型和交叉类型

    正文概述 掘金(lemonwater)   2021-02-19   1563

    写在前面

    最近写了个需求,当前存在两个列表数据,一个是提问列表,一个是回答列表。两个列表数据存在共同的数据结构:头像、名称、时间。于是我们根据数据后台的数据接口字段提炼出以下的ts类型。

    
    /**单个提问数据结构 */
    interface QsData {
      avator?: string
      time?: number | string
      name?: string
      quesitons: {
        title: string
        picture: string[]
      }
    }
    
    /**单个回答数据结构 */
    interface AsData {
      avator?: string
      time?: number | string
      name?: string
      answers: {
        text: string
        audio?: {
          url: string
          total: number
        }
      }
    } 
    

    类型拆分解耦

    很明显,优秀的代码根据DNR(do not repeat)原则,相同重复的声明片段是不好的。可以根据功能和模块拆分以上重复接口声明

    // 头像接口类型
    export interface DataAvator {
      avator?: string
      time?: number | string
      name?: string
    }
    
    // 提问数据接口类型
    export interface Qs {
      quesitons: {
        title: string
        picture: string[]
      }
    }
    
    // 问题接口数据类型
    export interface As {
      answers: {
        text: string
        audio?: {
          url: string
          total: number
        }
      }
    }
    

    接口混入

    但是我们需要的声明是刚开始那种复杂的数据类型,现在我们需要把简单的数据类型组装回去,怎么优雅的组装回去呢这是个问题?于是乎我想到了工具类型,借用工具类我们可以快速从简单的类型得到复杂的想要的类型。之前写过一篇走进工具泛型也有提及这块的ts知识。好了,我们现在可以来构造一个混入的ts工具类。

    type Mixin<T, X> = {
      [P in keyof (T & X)]: (T & X)[P]
    };
    

    它也可以更简单

    type Mixin<T, X> = T & X;
    

    我们使用Mixin去组装复杂的列表数据如下:

    // 用泛型混入,方便之后还会出现什么数据也带有头像等信息
    // 方便做拓展和复用
    type MixWithDataAvator<T> = Mixin<DataAvator, T>;
    
    // 组装Qs和As 拼接成想要的复杂数据类型
    export interface AskConfig {
      asker: MixWithDataAvator<Qs>
      answer?: MixWithDataAvator<As>
    }
    
    // 最终输出列表数组类型
    export type AskConfigList = AskConfig[];
    

    到这里为止一切都很顺利,相比之前我们一开始定义的两个数据声明已经非常松散了。不管是维护哪一部分的声明都不需要改动特别大。

    ts: & 和 |

    不得不说,这个前言真的特别长,现在才引出&和|符号。回到上面的Mixin部分,之所以能有这样的解决方案全靠了&符号。当我们把类型用&连接起来就是ts交叉类型,用|连接起来就是联合类型。起初笔者对这两个概念都不甚清晰,于是趁着项目中有用之处仔细捋了一捋。
    这两个类型概念可以用交集和并集的思维来理解。(PS:非常重要!先抛开数学集合中的交集和并集概念,网上大多的文章话不多说直接摆出数学集合中的概念其实是一种误导,因为跟以下的类集合完全不是一码事)。我们来看下图: 理解Ts联合类型和交叉类型 先看左边的类型交集:
    存在类型1:蓝色物体 类型2:小型物体,当两类型发生交集,那么交集出来的类型就是蓝色并且小型的物体。所以,交叉类型的理解就是类型交集产生出的新的类型,并且这个类型包含参与交集的类型的所有属性。
    再看右边的类型并集:
    存在类型1:蓝色物体 类型2:红色物体,当两类型发生并集,联合类型的理解就是类型并集之后产生的一个垃圾桶,所有参与并集的类型都像垃圾桶中的垃圾,当我们使用联合类型的时候,就像垃圾桶里捡垃圾,要么捡起来的是蓝色物体,要么就是红色物体。
    总结:&交叉类型:产生一个包含所有属性的新类型。 |联合类型:产生一个包含所有类型的选择集类型。

    联合类型

    interface A {
      name: string
      age: number
    }
    
    interface B {
      name: number
      id: string
    }
    
    type Union = A | B;
    const c: Union
    

    当我们使用联合类型赋值的时候,数据结构只能选择满足形如A或者形如B 理解Ts联合类型和交叉类型
    当我们使用联合类型读取属性的时候,只能获取其共同的属性名 ps(idea 语法提示)。如果访问的是非共同的属性,必须做好类型保护以防止bug。
    理解Ts联合类型和交叉类型

    交叉类型

    当我们使用交叉类型读取属性,可以获取所有类型的所有属性名,赋值的时候需要满足所有类型的结构
    理解Ts联合类型和交叉类型
    注意,非常重要,当我们交叉的类型中含有相同属性名但属性类型不一样的情况,该属性会成为never类型
    理解Ts联合类型和交叉类型
    原因也很简单:交叉操作,name不可能同时是number类型又是string类型,所以成为了never类型。

    never类型

    Never:即不存在的值的类型,按照上面的例子就是说,不存在属性name的值即是number又是string类型。也比较好理解。never类型也有使用场景,但我们在书写譬如if else / switch的多代码流的情况下对never类型赋值能及时抛出语法异常帮我们避免case遗漏的情况。想更加详细的了解never类型如何帮助代码检查这块 可以阅读这篇文章Never类型

    总结

    自个儿在网上搜索了许多文章看了许多复杂的解释,把自个儿理解的东西以更简单的方式梳理下来,2021年第一天返工也是第一篇文章~。但愿对一些同样对这两个概念还有疑惑的小伙伴有些许帮助吧。


    起源地下载网 » 理解Ts联合类型和交叉类型

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元