【TypeScript】深入解析 Truthiness Narrowing 与 Equality Narrowing

TypeScript 是 JavaScript 的超集,提供了类型安全的同时,也保留了 JavaScript 的灵活性。在类型推断和缩小方面,TypeScript 提供了许多高级功能,其中之一就是 “Truthiness Narrowing” 和 “Equality Narrowing”。本文将详细介绍这两个概念,并展示它们如何帮助开发者在编写 TypeScript 代码时避免潜在的错误。

一、什么是 Truthiness Narrowing?

1. Truthiness 的概念

“Truthiness” 可能是个新词,但在 JavaScript 中,它的应用非常普遍。在 JavaScript 中,很多表达式都可以用于条件语句中,例如 if 语句、&&|| 操作符等,而这些表达式的结果并不一定是布尔值。JavaScript 会将表达式强制转换为布尔值,以便在条件中使用。

例如,在 if 语句中,条件并不总是要求是布尔值,以下代码段演示了这种情况:

function getUsersOnlineMessage(numUsersOnline: number) {
  if (numUsersOnline) {
    return `${numUsersOnline} 位用户在线!`;
  }
  return "当前无人在线 :(";
}

在这个例子中,if (numUsersOnline) 实际上是通过将 numUsersOnline 强制转换为布尔值来决定分支选择的。TypeScript 在这种情况下自动推断出 numUsersOnline 是一个 number 类型,并利用 “Truthiness Narrowing” 进行类型缩小。

2. Truthy 与 Falsy 值

在 JavaScript 中,以下值会被强制转换为 false(即 falsy 值):

  • 0
  • NaN
  • ""(空字符串)
  • 0n(BigInt 类型的 0)
  • null
  • undefined

其他所有值都会被转换为 true(即 truthy 值)。通过 Boolean() 函数或使用 !! 操作符可以强制将任何值转换为布尔值。以下是一个例子:

Boolean("hello"); // 结果:true
!!"world";       // 结果:true

在这个例子中,"hello""world" 都是 truthy 值,它们都被强制转换为 true。TypeScript 可以通过这种 “Truthiness Narrowing” 机制来缩小类型的范围。

3. Truthiness Narrowing 的实际应用

让我们通过一个常见的例子来展示如何利用这种特性。我们有一个函数需要处理可能为 null 或者是一个字符串数组的值:

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    console.log(strs);
  }
}

在这个例子中,我们首先通过 if (strs) 检查 strs 是否是 truthy 的(即非 null),然后进一步缩小类型范围为 string[]string。这避免了处理 null 时可能出现的错误,如 TypeError: null is not iterable

4. Truthiness Narrowing 的陷阱

尽管 truthiness narrowing 非常有用,但它也有潜在的陷阱。例如,在以下代码中:

function printAll(strs: string | string[] | null) {
  if (strs) {
    if (typeof strs === "object") {
      for (const s of strs) {
        console.log(s);
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    }
  }
}

虽然看似没问题,但我们忽略了字符串 ""(空字符串)的情况,因为 "" 是一个 falsy 值。这会导致程序错误地将空字符串视为 false,而跳过其处理逻辑。因此,在编写代码时,特别是处理字符串时,开发者需要小心这种边缘情况。

二、什么是 Equality Narrowing?

1. Equality Narrowing 的概念

除了通过 truthiness 来缩小类型范围外,TypeScript 还支持通过相等性检查(===!====!=)来缩小类型范围。这种类型缩小被称为 “Equality Narrowing”。当 TypeScript 确定两个值相等时,它可以推断出这两个值的类型必须一致。

2. 使用相等性检查进行类型缩小

让我们来看一个具体的例子:

function example(x: string | number, y: string | boolean) {
  if (x === y) {
    console.log(x.toUpperCase()); // x 和 y 必定是 string
    console.log(y.toLowerCase());
  } else {
    console.log(x);
    console.log(y);
  }
}

在这个例子中,x === y 检查后,TypeScript 知道 xy 的类型必须是相同的,而它们唯一可能共享的类型是 string。因此,在 if 分支内,xy 的类型被自动缩小为 string,我们可以安全地调用字符串方法。

3. 特定字面值的相等性检查

我们可以通过检查特定的字面值来进一步缩小类型。例如,在前面提到的 printAll 函数中,我们可以通过检查 strs !== null 来确保 strs 不是 null,并进行类型缩小:

function printAll(strs: string | string[] | null) {
  if (strs !== null) {
    if (typeof strs === "object") {
      for (const s of strs) {
        console.log(s);
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    }
  }
}

通过这种方式,TypeScript 能够准确地推断出 strs 的类型,不再包含 null

4. 使用宽松的相等性检查进行类型缩小

在 JavaScript 中,==!= 是宽松的相等性运算符,它们不仅会比较值是否相等,还会尝试进行类型转换。TypeScript 也支持通过这些运算符进行类型缩小。以下是一个示例:

interface Container {
  value: number | null | undefined;
}
 
function multiplyValue(container: Container, factor: number) {
  if (container.value != null) {
    console.log(container.value);
    container.value *= factor;
  }
}

在这个例子中,container.value != null 检查后,TypeScript 知道 container.value 既不是 null 也不是 undefined,因此可以安全地执行数值运算。

三、Truthiness Narrowing 与 Equality Narrowing 的应用场景

1. 数据校验

在处理用户输入或外部 API 数据时,truthiness narrowing 和 equality narrowing 非常有用。开发者可以通过这些机制确保在操作数据之前,数据的类型是预期的。例如,在处理可能为空的 API 返回值时,我们可以使用 == null 来确保数据不为 nullundefined

2. 避免潜在的逻辑错误

正如我们在前面的例子中看到的,通过 truthiness narrowing,我们可以避免 nullundefined 引发的异常。但同时,开发者也需要意识到像空字符串 "" 这样的边缘情况,以免出现逻辑漏洞。

3. 简化复杂类型的操作

在处理复杂联合类型时,equality narrowing 提供了简化代码的能力。通过相等性检查,TypeScript 可以智能地缩小变量的类型范围,减少显式的类型断言或类型检查代码。

四、总结

Truthiness narrowing 和 equality narrowing 是 TypeScript 中非常强大的类型缩小机制。通过这些机制,开发者可以更加灵活地处理多种类型,并在编写代码时享受类型安全带来的优势。然而,开发者也应注意一些潜在的陷阱,特别是在处理 falsy 值时,应避免误判。结合 TypeScript 的类型推断能力和这些类型缩小特性,开发者能够编写出更加健壮、安全的代码。

推荐:


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter-Lu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值