TypeScript 中如何正确使用类型守卫 (Type Guard)

阅读时长 8 分钟读完

TypeScript 是一种强类型的 JavaScript 超集,它为开发者提供了更好的类型检查和代码提示功能。在 TypeScript 中,我们可以使用类型守卫(Type Guard)来帮助我们更好地处理类型检查。

本文将介绍 TypeScript 中类型守卫的概念、如何正确使用类型守卫以及一些常见的类型守卫场景。

什么是类型守卫?

类型守卫是一种 TypeScript 中的类型检查机制,它可以让我们在代码中更准确地判断变量的类型。

在 JavaScript 中,我们可以使用 typeofinstanceof 来判断变量的类型。但是在 TypeScript 中,由于类型的存在,这些方法可能会失效。

例如,下面的代码中,我们定义了一个 Person 类和一个 Cat 类,并创建了一个 Animal 类型的变量 animal。我们使用 typeof 来判断 animal 的类型,但是 TypeScript 编译器会提示错误:

-- -------------------- ---- -------
----- ------ -
  ----- -------
  ---- -------
-

----- --- -
  ----- -------
  ------ -------
-

--- ------- ------ - ----

-- ------- ------ --- --------- -
  ------------------------- -- ------ -------- ------ ---- --- ----- -- ---- ------- - -----
-

这是因为 typeof 只能判断基本类型,而不能判断复杂类型。所以我们需要使用类型守卫来判断变量的类型。

如何正确使用类型守卫?

在 TypeScript 中,类型守卫有多种实现方式。下面是几种常见的类型守卫实现方式。

typeof 类型守卫

对于基本类型,我们可以使用 typeof 来进行类型守卫。

例如,下面的代码中,我们定义了一个 sum 函数,它接收两个参数,如果这两个参数都是 number 类型,那么返回它们的和,否则返回 NaN。我们使用 typeof 来判断参数的类型:

-- -------------------- ---- -------
-------- ------ -------- -- --------- ------ -
  -- ------- - --- -------- -- ------ - --- --------- -
    ------ - - --
  - ---- -
    ------ ----
  -
-

------------------ ---- -- ------- -
-------------------- ---- -- ------- ---

instanceof 类型守卫

对于类的实例,我们可以使用 instanceof 来进行类型守卫。

例如,下面的代码中,我们定义了一个 Animal 类和一个 Cat 类,它继承自 Animal 类。我们创建了一个 Cat 类型的变量 cat,然后使用 instanceof 来判断它的类型:

-- -------------------- ---- -------
----- ------ -
  ----- -------
-

----- --- ------- ------ -
  ------ -------
-

--- ---- --- - --- ------
-------- - ------
--------- - --------

-- ---- ---------- ---- -
  ----------------- -- - --- ----- ------------ ---- ----- ----------------
- ---- -
  ----------------- -- --- - -------
-

自定义类型守卫函数

对于复杂类型,我们可以使用自定义类型守卫函数来进行类型守卫。

例如,下面的代码中,我们定义了一个 Person 类和一个 Cat 类,它们都有一个 name 属性。我们创建了一个 Animal 类型的变量 animal,然后使用一个自定义类型守卫函数 isPerson 来判断它的类型:

-- -------------------- ---- -------
----- ------ -
  ----- -------
  ---- -------
-

----- --- -
  ----- -------
  ------ -------
-

--- ------- ------ - ----

-------- ---------------- ------ - ----- ------ -- ------ -
  ------ ------- -- ----------- --- ----------
-

-- ------------------ -
  ----------------- -- - ------ ----- --------------- ---- --- -----------------
- ---- -
  ----------------- -- - --- ----- --------------- ---- ----- -------------------
-

在上面的代码中,我们定义了一个 isPerson 函数,它接收一个 Person | Cat 类型的参数,并返回一个布尔值。当这个参数是 Person 类型时,返回 true,否则返回 false。在 if 语句中,我们使用 isPerson 函数来判断 animal 的类型。

常见的类型守卫场景

类型守卫与联合类型

在 TypeScript 中,联合类型是指一个变量可以是多种类型中的一种。例如,下面的代码中,我们定义了一个 Person 类和一个 Cat 类,然后创建了一个 Person | Cat 类型的变量 animal

-- -------------------- ---- -------
----- ------ -
  ----- -------
  ---- -------
-

----- --- -
  ----- -------
  ------ -------
-

--- ------- ------ - ----

当我们使用 animal 变量时,由于它可以是 Person 类型或 Cat 类型,所以 TypeScript 编译器无法准确地判断 animal 的类型。这时,我们可以使用类型守卫来帮助编译器判断变量的类型。

例如,下面的代码中,我们使用自定义类型守卫函数 isPerson 来判断 animal 的类型:

-- -------------------- ---- -------
-------- ---------------- ------ - ----- ------ -- ------ -
  ------ ------- -- ----------- --- ----------
-

-- ------------------ -
  ----------------- -- - ------ ----- --------------- ---- --- -----------------
- ---- -
  ----------------- -- - --- ----- --------------- ---- ----- -------------------
-

在上面的代码中,我们使用 isPerson 函数来判断 animal 的类型。如果 animalPerson 类型,就输出人的信息;否则就输出猫的信息。

类型守卫与可选属性

在 TypeScript 中,我们可以为类的属性指定可选属性,即这个属性可以有值,也可以没有值。例如,下面的代码中,我们定义了一个 Person 类和一个 Cat 类,它们都有一个可选的 age 属性:

-- -------------------- ---- -------
----- ------ -
  ----- -------
  ----- -------
-

----- --- -
  ----- -------
  ------ -------
  ----- -------
-

当我们使用 age 属性时,由于它是可选属性,所以 TypeScript 编译器无法准确地判断这个属性是否存在。这时,我们可以使用类型守卫来判断属性是否存在。

例如,下面的代码中,我们使用自定义类型守卫函数 hasAge 来判断 animal 是否有 age 属性:

-- -------------------- ---- -------
-------- -------------- ------ - ----- ------ -- ------ -
  ------ ------- -- ----------- --- ----------
-

--- ------- ------ - - ----- ----- --
--- ---- --- - - ----- -------- ------ ------- --

-- ---------------- -
  ----------------- -- - ------ ----- --------------- ---- --- -----------------
- ---- -
  ----------------- -- - --- ----- ------------ ---- ----- ----------------
-

在上面的代码中,我们使用 hasAge 函数来判断 animal 是否有 age 属性。如果 animalage 属性,就输出人的信息;否则就输出猫的信息。

总结

类型守卫是 TypeScript 中的一个重要特性,它可以帮助我们更准确地判断变量的类型。在本文中,我们介绍了类型守卫的概念、如何正确使用类型守卫以及一些常见的类型守卫场景。希望本文可以帮助大家更好地使用 TypeScript。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/660684d1d10417a2224d08d7

纠错
反馈