zoukankan      html  css  js  c++  java
  • TypeScript 中的类型保护

    在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况:

    interface Bird {
      	// 独有方法
        fly();
      	// 共有方法
        layEggs();
    }
    
    interface Fish {
      	// 独有方法
        swim();
      	// 共有方法
        layEggs();
    }
    
    function getSmallPet(): Fish | Bird {
        // ...
    }
    
    let pet = getSmallPet();
    pet.layEggs(); // 正常
    pet.swim();    // ts 报错
    

    如上所示,getSmallPet 函数中,既可以返回 Fish 类型的对象,又可以返回 Bird 类型的对象。由于返回的对象类型不确定,所以使用联合类型对象共有的方法时,一切正常,但是使用联合类型对象各自独有的方法时,ts 会报错。

    那么如何解决这个问题呢?最粗暴的方法当然是将联合类型转换为 any,不过这种方法不值得提倡,毕竟我们写的是 TypeScript 而不是 AnyScript。

    此时,我们使用今天的主角——类型保护,闪亮登场,它可以完美的解决这个问题。

    孔乙己说过,茴香豆有四种写法,同理,实现类型保护,也有四种写法。

    类型断言

    类型断言是最常用的一种类型保护方法,即直接指定类型。由于,TypeScript 中识别的类型大多是靠 TypeScript 的自动类型推算算出来的,所以会出现上面所说的那种问题,即 TypeScript 不知道具体对象类型是什么,所以不确定有没有联合类型各自独有的方法。

    当使用类型断言直接指定类型时,相当于你让 TypeScript 开启了上帝模式,可以直接知道具体类型是联合类型中的那个,此时再使用对象的独有方法就符合 TypeScript 的推断了。

    interface Bird {
      // 独有方法
      fly();
      // 共有方法
      layEggs();
    }
    
    interface Fish {
      // 独有方法
      swim();
      // 共有方法
      layEggs();
    }
    
    function getSmallPet(): Fish | Bird {
      // ...
    }
    
    let pet = getSmallPet();
    pet.layEggs(); // 正常
    // 通过鸭子类型来进行判断
    if ((pet as Bird).fly) {
      // 类型断言
      (pet as Bird).fly()
    } else {
      // 类型断言
      (pet as Fish).swim()
    }
    

    如果嫌弃通过 as 来进行类型断言不够上流,还可以使用类泛型的写法,即:

    let pet = getSmallPet();
    pet.layEggs(); // 正常
    // 通过鸭子类型来进行判断
    if ((<Bird>pet).fly) {
      (<Bird>pet).fly()
    } else {
      (<Fish>pet).swim()
    }
    

    tips:友情提示,虽然使用类泛型写法进行类型断言看起来高端一些,但是由于在 tsx 中语法存在歧义,所以为了统一起见,推荐使用 as 的方法进行类型断言。

     

    in 语法

    在 js 中,我们经常使用 in 语法来判断指定的属性是否在指定的对象或其原型链中。

    同理,在 TypeScript 中,我们可以通过这种方法确认对象类型。

    interface Bird {
      // 独有方法
      fly();
      // 共有方法
      layEggs();
    }
    
    interface Fish {
      // 独有方法
      swim();
      // 共有方法
      layEggs();
    }
    
    function getSmallPet(): Fish | Bird {
      // ...
    }
    
    let pet = getSmallPet();
    pet.layEggs(); // 正常
    // 使用 in 语法进行类型保护
    if ('fly' in pet) {
      pet.fly()
    } else {
      pet.swim()
    }
    

    原理同类型断言一样,都是引导 TypeScript 的类型推断,确定对象类型。

    instanceof 语法

    当联合类型中使用的是 class 而不是 interface 时,instanceof 语法就派上用场了,通过 instanceof 语法可以区分不同的 class 类型。

    class Bird {
      // 独有方法
      fly() {};
      // 共有方法
      layEggs() {};
    }
    
    class Fish {
      // 独有方法
      swim() {};
      // 共有方法
      layEggs() {};
    }
    
    function getSmallPet(): Fish | Bird {
      // ...
    }
    
    let pet = getSmallPet();
    pet.layEggs(); // 正常
    // 使用 in 语法进行
    if (pet instanceof Bird) {
      pet.fly()
    } else {
      pet.swim()
    }

    佛山vi设计https://www.houdianzi.com/fsvi/ 豌豆资源搜索大全https://55wd.com

    typeof 语法

    typeof 语法不同于 in 语法以及 instanceof 语法,in 语法以及 instanceof 语法都是用来引导类型推断进行不同对象类型推断,而 typeof 语法常用于基本类型的推断(或者是联合使用基本类型和对象类型)。

    简而言之,当使用 typeof 能够区分联合类型中的不同类型时,即可使用它。

    function getSmallPet(): number | string {
      // ...
    }
    
    let pet = getSmallPet();
    if (typeof pet === 'number') {
      pet++
    } else {
      pet = Number(pet) + 1
    }

    总结

    就如茴香豆的四种写法的本质依然是茴香豆一样,类型保护的四种写法的本质也是一样的,即,引导 TypeScript 中的类型推断将类型推断的多选题变为单选题,这就是类型保护的本质。

  • 相关阅读:
    jchdl
    jchdl
    UVa 10256 (判断两个凸包相离) The Great Divide
    UVa 11168 (凸包+点到直线距离) Airport
    LA 2572 (求可见圆盘的数量) Kanazawa
    UVa 10652 (简单凸包) Board Wrapping
    UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!
    UVa 10674 (求两圆公切线) Tangents
    UVa 11796 Dog Distance
    LA 3263 (平面图的欧拉定理) That Nice Euler Circuit
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/13847535.html
Copyright © 2011-2022 走看看