TypeScript 规范在 §4.15.6 中规定了有关 && 操作员:

&& 运算符允许操作数为任何类型并生成 结果与第二个操作数类型相同.

在 JavaScript 中, && 如果操作数为假,则返回第一个操作数,否则返回第二个操作数 (参见 ECMA-262 §11.11).

这意味着如果左操作数为假, && 将返回与左操作数类型匹配的值。例如,

typeof ( false && {}      ) === "boolean" // true
typeof ( ''    && 1       ) === "string"  // true
typeof ( null  && "hello" ) === "object"  // true
typeof ( NaN   && true    ) === "number"  // true

根据上面引用的规则,Typescript 将 不正确地 预测上述表达式的类型为 Object, Number, StringBoolean, , 分别。

我错过了什么吗?是否有充分的理由来创建一个类型 && 表达式与第二个操作数的类型匹配吗?结果类型不应该像 || 运算符,并返回两个操作数的最佳公共类型,以及 Any 如果没有最佳通用类型?

有帮助吗?

解决方案

长话短说,这里没有让所有人满意的解决方案。

考虑一下这个常见的习语:

var customer = GetCustomer(...); // of type 'Customer'
var address = customer && customer.address;
if(address) {
    printAddressLabel(address); // Signature: (Address) => void
} else {
    // Couldn't find the customer or the customer has no address on file
}

放弃并决定“地址”为“任意”是非常蹩脚的,因为“客户”和“地址”之间没有最佳通用类型。

在大多数使用 && 运算符的情况下,类型 已经 match 或 && 正在以如上所述的值合并方式使用。无论哪种情况,返回正确操作数的类型都会为用户提供预期的类型。

虽然此时类型安全在技术上已经崩溃,但它并没有以可能导致错误的方式进行。您要么要测试结果值的真实性(在这种情况下,类型或多或少不相关),要么要对某些操作使用假定的正确操作数(上面的示例同时执行这两种操作)。

如果我们查看您列出的示例并假装左操作数不确定是真还是假,然后尝试编写对返回值进行操作的理智代码,它就会变得更加清晰 - 您无能为力 带有“false && {}”,尚未进入“任何”参数位置或真实性测试。


附录

由于有些人不相信上述内容,这里有一个不同的解释。

让我们假设 TypeScript 类型系统添加了三种新类型: Truthy<T>, Falsy<T>, , 和 Maybe<T>, ,表示类型的可能的真值/假值 T. 。这些类型的规则如下:

  1. Truthy<T> 行为完全像 T
  2. 您无法访问 的任何属性 Falsy<T>
  3. 类型的表达式 Maybe<T>, ,当用作条件时 if 块,变成 Truthy<T> 在同一个身体里 if 块和一个 Falsy<T> 在里面 else 堵塞

这会让你做这样的事情:

function fn(x: Maybe<Customer>) {
   if(x) {
      console.log(x.address); // OK
   } else {
      console.log(x.phone); // Error: x is definitely falsy
   }
   console.log(x.name); // Warning: x might be falsy!
}

到目前为止还不错。现在我们可以弄清楚 && 运算符的类型规则是什么。

  • Truthy<T> && x 应该是一个错误 - 如果知道左边是真的,你应该刚刚写 x
  • Falsy<T> && x 应该是一个错误 - 如果已知左侧是假的, x 是无法访问的代码
  • Maybe<T> && x 应该产生...什么?

我们知道结果 Maybe<T> && x 将是类型的虚假值 T, , 或者 x. 。它无法产生 Truthy<T> (除非 T == 的类型 x 在这种情况下,整个讨论就没有意义了)。我们称这个新类型为 Falsy<T> XOR Maybe<U>.

应该遵守什么规则 Falsy<T> XOR Maybe<U> 是?

  • 显然,您不能使用 T 在上面。如果该值是类型 T, ,它是虚假的,并且使用不安全。
  • 您应该能够将它用作 Maybe<U>, , 自从 Falsy<T>Falsy<U> 有相同的行为
  • 您不应该能够使用以下属性 U, ,因为该值仍然可能是假的。
  • 如果你在一个 if 测试,那么它应该成为 Truthy<U> 在那个街区 if 陈述

换句话说, Falsy<T> XOR Maybe<U> Maybe<U>. 。它遵循所有相同的规则。您根本不需要通过添加这个奇怪的东西来使类型系统变得复杂 XOR 类型,因为符合您需要的所有规格的类型已经存在。

这有点像给某人一个盒子并说“这要么是一个空的垃圾箱,要么是一整箱的可回收物”。您可以安全地将盒子里的东西倒进回收箱。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top