浅谈TypeScript的类型保护机制

所属分类: 网络编程 / JavaScript 阅读数: 1313
收藏 0 赞 0 分享

在编写 TS 时,它做了比我们看到的更多的事情,例如类型保护机制。让我们编写的代码更加严谨,至于怎么回事,让我们来看看吧。

由于这些机制的存在,就算你仍旧以 JS 原生的书写方式,也能帮助你提前发现代码中潜在的问题。(对于认为 TS 语句更复杂的人,也能实现 0 门槛,不改变已有的习惯也能享受静态检测的好处。)

类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域内的类型。

为了更简单的理解,我们首先声明一个联合类型用于举例:

interface Bird {
 fly(): any;
 layEggs(): any;
}

interface Fish {
 swim(): any
 layEggs(): any
}

type Pet = Bird | Fish;

无类型保护时报错

function fn(pet: Pet) { 
 pet.layEggs(); // okay
 pet.swim();  // Error: Property 'swim' does not exist on type 'Bird | Fish'.
}

因为 TS 并不知道 pet 的实例是 Bird 还是 Fish,因此为了谨慎起见,在未手动声明类型时 TS 中只能调用 联合类型 中的 公共方法,例子中未 layEggs() 方法。除非你在调用指定对象数据的属性或方法前,明确告诉 TS 数据对象是一个具体的类型。

类型断言实现类型保护

我需要使用 <Fish>pet 的 类型断言,来告诉 TS 目标对象是什么类型:

function fn(pet: Fish | Bird) {
 if ((<Fish>pet).swim) {
  (<Fish>pet).swim();
 } else {
  (<Bird>pet).fly();
 }
}

虽然这样的断言满足了我们的需求,但并不好方便,需要在各处都进行引用。
备注:如果在编写 tsx 时,你需要将 (<Fish>pet) 写成 (pet as Fish),因为在 tsx 中尖括号 <> 有特殊的含义。

函数中使用 is 定位类型

我们将上面的 if 内的判断封装到函数中,获得更方便的类型保护方式,此函数必须使用 parameterName is Type 的 类型谓语:

function isFish<T>(pet: Fish | Bird): pet is Fish {
 return !!(<Fish>pet).swim;
}

此函数必须返回为 boolean 类型才生效,当返回 true 时则类型定位为 Fish ,返回 false 时则定位为 Fish 之外的类型(多个类型则以 联合类型 定位)。

function fn(pet: Fish | Bird ) { 
 if (isFish(pet)) {
  pet.swim(); // 因 is 语句的生效,此语句块中类型 let pet: Fish
 } else {
  pet.fly(); // 排除 Fish 之外的类型,此语句块中类型 let pet: Bird
 }
}

需要注意是除了 if 中类型生效,TS 还能自动推断出 else 中的类型。

就算你不使用 TS 这些特定的语句,也能享受 类型保护机制 的好处,下面让我们来看看。

使用 typeof 进行类型保护

如果子类型是只是 number、string、boolean、symbol 这几种数据类型,则可以直接使用 typeof 关键字,TS 能够检测并提供类型保护,我们直接引用官方给的例子:

function padLeft(value, padding): string {
  if (typeof padding === "number") {
    return Array(padding + 1).join(" ") + value;  // let padding: number
  }
  else {
    return padding + value;  // let padding: string
  }
}
  
const t1 = padLeft("world", 6);    // "   world"
const t2 = padLeft("world", "hello "); // "hello world"

使用 instanceof 进行类型保护

由于现在前端对于 面向对象 的开发项目越来越多,因此类的引用也更多了。那么类型保护用在此时,可谓是更加有重要,我们使用 instanceof 来达到这一效果:

interface IA { x(): void; }
interface IB { y(): void; }

class A implements IA {
 x() { }
}
class B implements IB {
 y() { }
}

function fn(e: A | B) {
 if (e instanceof A)
  e.x(); // let e: A
 else
  e.y(); // let e: 
}

基于类型保护机制,在语句块中编辑器会给予指定类型的 方法提示,以及类型检测时会提示用户。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

js单独获取一个checkbox看其是否被选中

这篇文章主要与大家分享js获取一个checkbox看其是否被选中的具体实现,很简单,但很实用,需要的朋友可以参考下
收藏 0 赞 0 分享

js变量、作用域及内存详解

本文主要详细分析了JS变量,作用域以及内存问题,同时附上非常多的实例,方便大家理解这3个概念,是篇不可多得的文章,希望对大家有所帮助
收藏 0 赞 0 分享

深入理解javascript作用域和闭包

作用域和作用域链是javascript中非常重要的特性,对于他们的理解直接关系到对于整个javascript体系的理解,而闭包又是对作用域的延伸,也是在实际开发中经常使用的一个特性,实际上,不仅仅是javascript,在很多语言中都提供了闭包的特性。
收藏 0 赞 0 分享

IE6 hack for js 集锦

本文主要讲诉了使用js实现网站功能兼容IE6,非常的实用的小技巧,有需要的朋友可以参考下
收藏 0 赞 0 分享

Javascript的setTimeout()使用闭包特性时需要注意的问题

这篇文章主要介绍了Javascript的setTimeout(0)使用闭包特性时需要注意的问题,需要的朋友可以参考下
收藏 0 赞 0 分享

常用的jquery模板插件——jQuery Boilerplate介绍

Query Boilerplate是一个不错的jQuery插件开发工具,使用这个工具可以帮助你快速的构建一个jQuery框架。这个工具提供你很多评论用以帮助你使得开发变得简单和直接,它是个真正的面对对象的工具,你可以实现公开或者私有的方法或者公开或者私有的属性。
收藏 0 赞 0 分享

深入理解javascript构造函数和原型对象

对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅。。(哔!)。
收藏 0 赞 0 分享

深入理解javascript原型链和继承

这篇文章主要介绍了javascript原型链和继承的概念,以及使用原型链实现继承、经典继承、组合式继承、寄生组合式继承。非常实用,是篇非常不错的文章,这里推荐给大家。
收藏 0 赞 0 分享

再探JavaScript作用域

这篇文章主要介绍了再探JavaScript作用域,本文用简洁的语言和直观的测试结果图片给大家讲解JavaScript的作用域,需要的朋友可以参考下
收藏 0 赞 0 分享

JavaScript获取图片真实大小代码实例

这篇文章主要介绍了JavaScript获取图片真实大小代码实例,本文使用onload事件来获取图片的真实大小,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多