😀
TypeScript 通过引入类型系统,使得 JavaScript 开发更加健壮和可维护。其中,类型收缩(Narrowing)和类型守卫(Type Guards)是确保代码类型安全的重要工具。本文主要详细探讨这两个机制,为编写更健壮的 TypeScript 代码打下理论基础,同时也方便本人学习和记录。

📝 简介

在介绍类型收缩和类型守卫之前,先要了解一下它们的定义。

什么是类型收缩

类型收缩是指 TypeScript 可以通过代码逻辑分析变量的类型,从而将变量的类型从一个更广泛的集合(如Any)缩小到更具体的类型(如number)。这种分析通常在控制流语句(如 if、switch、循环等)中进行。

观点2

类型守卫是特定的表达式,这些表达式在运行时检查类型信息,从而使 TypeScript 可以在代码的某个分支中缩小变量的类型范围。
  • 常见的类型守卫包括:
    • typeof
    • instanceof
    • in 操作符
    • 自定义类型守卫

🤗 类型守卫的基础

使用 typeof 进行类型守卫

  • typeof 操作符可以在运行时检查变量的基本类型。
  • TypeScript 可以利用这一点来缩小类型范围。
在上面的例子中,通过检查 padding 的类型,可以分别处理 number 和 string 类型的 padding,从而确保了类型安全。

使用 instanceof 进行类型守卫

  • instanceof 操作符用于检查一个对象是否是某个构造函数的实例。
  • 同样,TypeScript 可以利用这一点来缩小类型范围。
在上面的例子中,通过检查 x 是否为 Date 的实例,从而可以推断出 x 的具体类型。

使用 in 操作符进行类型守卫

  • in 操作符用于检查对象是否具有特定属性。
  • 同样的,TypeScript 也可以利用这一点来缩小类型范围。
在上面的这个例子中:
  • Fish 和 Bird 接口定义了两种动物类型。
  • move 函数接受 Fish | Bird 类型的参数,并使用 in 操作符来检查是否存在 swim 或 fly 方法,这是一种类型守卫的使用方式。
  • 通过检查 swim 属性,TypeScript 能够将 animal 的类型从 Fish | Bird 缩小到 Fish。
  • 如果 swim 属性不存在,代码会检查 fly,并相应地将类型缩小到 Bird。

真值收缩

  • 在 JavaScript 中,诸如 0、NaN、空字符串 ""、null、undefined 等值在条件判断中会被转换为 false。
  • 因此,在 TypeScript 中,可以利用这种机制来缩小类型。
使用真值检查防止运行时错误:
在上面的代码例子中,主要通过检查 strs 是否为真值,从而避免 null 值导致的运行时错误。

相等性检查进行类型收缩

  • TypeScript 使用 ===、!== 等操作符来进行相等性检查,从而缩小类型范围。
在上面的代码例子中,主要是通过检查 x 和 y 是否相等,从而推断出它们的具体类型。

🤌 高级类型守卫技术

用户定义的类型守卫

  • 有时,我们需要更灵活的类型检查,可以通过定义用户自定义的类型守卫来实现。
  • 一个类型守卫是一个返回类型为类型谓词的函数:
在上面的代码例子中,主要通过用户自定义的isFish 函数来检查 pet 是否为 Fish 类型,并相应地缩小类型范围。

鉴别联合(Discriminated Unions)

  • 鉴别联合是指通过一个公共属性来区分联合类型中的不同类型。
在上面的代码示例中,主要是通过检查 kind 属性,从而能够推断出具体的形状类型。

🙉 控制流分析与类型收缩

  • 控制流分析是指 TypeScript 可以根据代码的执行路径来分析变量的类型,从而进行类型收缩。例如:

😋 使用 never 类型进行完整性检查

  • never 类型表示不应该存在的状态。
  • 当联合类型的所有可能性都被移除时,则会使用 never 类型。

示例说明

  • 关于 never 的例子比较长,分几个代码片段进行说明。
  • 假设我们有一个联合类型,表示一个简单的事件系统中的几种不同类型的事件。每种事件都有一个独特的类型标记(type 字段),我们希望根据这个类型标记来处理事件。
  • 定义事件类型:首先,需要定义一个包含几种不同类型的事件的联合类型:
    • 处理事件的函数:接下来,编写一个函数来处理这些事件。主要使用 switch 语句来检查每个事件的类型,并对每种类型进行处理。
      • 调用函数:

        优点

        使用 never 类型进行完整性检查的主要优点是它提供了一种安全机制,确保在联合类型可能发生变化时(例如新增类型),能够及时更新处理逻辑。这种模式特别适用于那些经常更改或可能扩展的代码,如处理外部数据或事件系统的代码。

        🧑‍💻 总结

        通过类型收缩和类型守卫,TypeScript 提供了强大的工具来确保代码的类型安全。这些机制使得我们可以编写更健壮、更易于维护的代码。了解并掌握这些特性,能够显著提升开发效率和代码质量。

        📎 参考\推荐

        💡
        本篇博客内容,主要是借助GPT的文档协作能力,并基于官方文档进行整理而出的。
         
        TypeScript——对象类型、属性、签名JavaScript——prototype与__proto__