• 【TypeScript】类型兼容:如何判断一个类型是否可以赋值给其他类型?


    自我介绍:大家好,我是吉帅振的网络日志(其他平台账号名字相同),互联网前端开发工程师,工作5年,去过上海和北京,经历创业公司,加入过阿里本地生活团队,现在郑州北游教育从事编程培训。

    一、前言

    TypeScript 中类型的兼容性都是基于结构化子类型的一般原则进行判定的。

    二、子类型 结构类型 可继承和可实现

    (1)子类型

    从子类型的角度来看,所有的子类型与它的父类型都兼容,如下代码所示:

    {
      const one = 1;
      let num: number = one; // ok
      interface IPar {
        name: string;
      }
      interface IChild extends IPar {
        id: number;
      }
      let Par: IPar;
      let Child: IChild;
      Par = Child; // ok
      class CPar {
        cname = '';
      }
      class CChild extends CPar {
        cid = 1;
      }
      let ParInst: CPar;
      let ChildInst: CChild;
      ParInst = ChildInst; // ok
      let mixedNum: 1 | 2 | 3 = one; // ok
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在示例中的第 3 行,我们可以把类型是数字字面量类型的 one 赋值给数字类型的 num。在第 12 行,我们可以把子接口类型的变量赋值给 Par。在第 21 行,我们可以把子类实例 ChildInst 赋值给 ParInst。因为成员类型兼容它所属的类型集合(其实联合类型和枚举都算类型集合,这里主要说的是联合类型),所以在示例中的第 22 行,我们可以把 one 赋值给包含字面类型 1 的联合类型。由子类型组成的联合类型也可以兼容它们父类型组成的联合类型,如下代码所示:

      let ICPar: IPar | CPar;
      let ICChild: IChild | CChild;
      ICPar = ICChild; // ok
    
    • 1
    • 2
    • 3

    在示例中的第 3 行,因为 IChild 是 IPar 的子类,CChild 是 CPar 的子类,所以 IChild | CChild 也是 IPar | CPar 的子类,进而 ICChild 可以赋值给 ICPar。

    (2)结构类型

    类型兼容性的另一准则是结构类型,即如果两个类型的结构一致,则它们是互相兼容的。比如拥有相同类型的属性、方法的接口类型或类,则可以互相赋值。

    {
      class C1 {
        name = '1';
      }
      class C2 {
        name = '2';
      }
      interface I1 {
        name: string;
      }
      interface I2 {
        name: string;
      }
      let InstC1: C1;
      let InstC2: C2;
      let O1: I1;
      let O2: I2;
      InstC1 = InstC2; // ok
      O1 = O2; // ok
      InstC1 = O1; // ok
      O2 = InstC2; // ok
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    因为类 C1、类 C2、接口类型 I1、接口类型 I2 的结构完全一致,所以在第 18-19 行我们可以把类 C2 的实例 InstC2 赋值给类 C1 的实例 Inst1,把接口类型 I2 的变量 O2 赋值给接口类型 I1 的变量 O1。在第 20~21 行,我们甚至可以把接口类型 I1 的变量 O1 赋值给类 C1 的实例,类 C2 的实例赋值给接口类型 I2 的变量 O2。另外一个特殊的场景:两个接口类型或者类,如果其中一个类型不仅拥有另外一个类型全部的属性和方法,还包含其他的属性和方法(如同继承自另外一个类型的子类一样),那么前者是可以兼容后者的。

    {
      interface I1 {
        name: string;
      }
      interface I2 {
        id: number;
        name: string;
      }
      class C2 {
        id = 1;
        name = '1';
      }
      let O1: I1;
      let O2: I2;
      let InstC2: C2;
      O1 = O2;
      O1 = InstC2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在示例中的第 16~17 行,我们可以把类 C2 的实例 InstC2 和接口类型 I2 的变量 O2 赋值给接口类型 I1 的变量 O1,这是因为类 C2、接口类型 I2 和接口类型 I1 的 name 属性都是 string。不过,因为变量 O2、类 C2 都包含了额外的属性 id,所以我们不能把变量 O1 赋值给实例 InstC2、变量 O2。这里涉及一个需要特别注意的特性:虽然包含多余属性 id 的变量 O2 可以赋值给变量 O1,但是如果我们直接将一个与变量 O2 完全一样结构的对象字面量赋值给变量 O1,则会提示一个 ts(232

  • 相关阅读:
    NEDC、WLTC、CLTC,三种汽车能源消耗测试标准有什么区别?
    Seata AT模式下的源码解析(一)
    python 操作redis 消息队列
    RabbitMQ之TTL机制
    新型超导Fluxonium量子比特正加速量子计算机的创建
    中电金信:技术实践|Flink维度表关联方案解析
    BUUCTF zip伪加密 1
    SSM整合(五)
    C++ 提高编程
    Maven简介
  • 原文地址:https://blog.csdn.net/qq_42451979/article/details/126409871