• typescript高级类型-类型兼容性


    类型兼容性

    在 TypeScript 中,对象类型兼容性是指当一个对象赋值给另一个对象时,是否满足类型要求。TypeScript 的类型兼容性是基于结构子类型而不是名义类型的,这意味着只要源类型的属性和方法满足目标类型的要求,就认为两个类型是兼容的。

    TypeScript 的对象类型兼容性规则如下:

    1. 源类型必须具有目标类型中的所有必需属性。
    2. 源类型的可选属性必须在目标类型中也存在,并且类型匹配。
    3. 源类型不能有目标类型中不存在的属性。
    4. 目标类型可以有额外的属性,但是源类型的属性必须是目标类型属性的子集。

    两种类型系统:1StructuralType System (结构化类型系统)2 NominalType System (标明类型系统)。
    TS 采用的是结构化类型系统,也叫做 ducktyping (鸭子类型…?什么???你不明白什么叫鸭子类型? 伟大的鲁迅先生说过如果一个东西,看起来是鸭子,叫起来像鸭子,吃起来像鸭子,那它就是鸭子!!!),
    类型检查关注的是值所具有的形状。
    也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。

    class Point  x: number; y: number
    class Point2D { x: number; y: number
    const p: Pointt= new Point2DC
    
    • 1
    • 2
    • 3

    解释:

    1. Point和Point2D是两个名称不同的类
    2. 变量p的类型被显示标注为Point类型,但是,它的值却是Point2D 的实例,并且没有类型错误。
    3. 因为TS 是结构化类型系统,只检查Point和 oint2D 的结构是否相同(相同,都具有和y 两个属性,属性类型也相同)。
    4. 但是,如果在NominalType System 中(比如,C#、Java等),它们是不同的类,类型无法兼容。

    对象间的兼容性

    tips
    :在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法并不准确。
    更准确的说法: 对于对象类型来说,y 的成员至少与相同,则X 兼容y(成员多的可以赋值给少的)。

    class Point  x: number; y: number
    class Point3D [ x: number; y: number; z: numberconst p: 
    Point = new Point3()
    
    • 1
    • 2
    • 3

    解释:
    Point3D的成员至少与Point相同,则Point兼容Point3D
    2.所以,成员多的Point3D可以赋值给成员少的Point。

    接口之间的兼容性

    除了class 之外,TS中的其他类型也存在相互兼容的情况,包括:1接口兼容性2函数兼容性等接口之间的兼容性,类似于 class。并且,class和 interface 之间也可以兼容。

    //声明一个拥有两个number成员接口Point
    interface Point { x: number; y: number }
    //声明一个拥有两个number成员接口Point2D
    interface Point2D { x: number; y: number }
    
    // 声明一个变量p1,类型为Point 
    let p1: Point = { x: 10, y: 20 };
    //声明一个变量p2 类型为ponit2D,并将p1赋值给它
    // 可以看到并没有报错
    // 因为接口也拥有兼容性,只要结构一致
    let p2: Point2D = p1
    
    //再声明一个拥xyz有三个number成员接口的Point3D
    interface Point3D { x: number; y: number; z: number }
    //声明一个Point3D类型变量p3
    let p3: Point3D = { x: 10, y: 20, z: 30 }
    //将p3赋值给p2
    p2 = p3
    
    // 再声明一个Point3D类
    class Point3D { x: number; y: number; z: number }
    
    //声明一个Point2D类型变量p4,将Point3D实例赋值给它
    // 可以看到也没有报错
    let c3: Point2D = new Point3D()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    函数之间的兼容性

    函数之间兼容性比较复杂,需要考虑:

    1. 参数个数
    2. 参数类型
    3. 返回值类型

    参数个数 参数多的兼容参数少的(或者说,参数少的可以赋值给多的) 示例如下

    // 定义一个名为 "F1" 的函数类型:没有返回值,只有一个number参数
    type F1 = (a: number) => void
    // 定义一个名为 "F2" 的函数类型:没有返回值,只有两个number参数
    type F2 = (a: number, b: number) => void;
    // 声明变量f1:类型注解为F1并初始化
    let f1: F1 = (a: number) => { }
    //声明一个变量f2:类型注解为f2,再将f1赋值给f2
    // 可以看到并没有报错
    let f2: F2 = f1
    
    // 声明一个数组arr
    const arr = ['a', 'b', 'c']
    // 调用数组的foreach函数并传入一个无参箭头函数
    arr.forEach(() => { })
    // 调用数组的foreach函数并传入一个一个参数的箭头函数
    // 可以看到因为函数的类型兼容性,多个参数的函数能兼容参数少的函数
    // 所以这里没有报错
    arr.forEach(x => { }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. 参数少的可以赋值给参数多的,所以,f1 可以赋值给f2。
    2. 数组 forEach 方法的第一个参数是回调函数,该示例中类型为: (value:string,index: number, array: stringl)=>void.
    3. 在J5中省略用不到的函数参数实际上是很常见的,这样的使用方式,促成了T5中函数类型之间的兼容性
    4. 并且因为回调函数是有类型的,所以,TS会自动推导出参数item、index、array的类型。

    参数类型 相同位置的参数类型要相同(原始类型)或兼容(对象类型)

    如下我们可以看到,当我们将拥有不同参数类型的f1赋值给f3时报错了

    在这里插入图片描述

    解释:函数类型F2兼容函数类型F1,因为F1和F2的第一个参数类型相同。

    返回值类型** 只关注返回值类型本身即可**

    如果返回值类型是原始类型,此时两个类型要相同,比如,左侧类型F5 和 F6。
    如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,右侧类型F7 和 F8。

    在这里插入图片描述

  • 相关阅读:
    金融企业Web应用什么防火墙好?
    微信小程序SDK使用实例
    地图加载wmts格式底图的配置
    创建定时任务——crontab的使用
    【前端2】jquary(选择器),bootstrap(布局容器),vue(创建实例)
    0基础24岁女硕士生,想转行做月薪30k的测试开发,需要从什么开始学习?
    阿里云ECS服务器安装docker
    计算机组成原理---第五章中央处理器---指令流水线---选择题
    企业微信把人移出会有显示吗?如何移出?
    ElasticSearch讲解(开源的、高拓展的分布式全文检索引擎)
  • 原文地址:https://blog.csdn.net/weixin_44368963/article/details/136185374