TypeScript规范在§4.15.6中说明了&&
运算符:
&&运算符允许操作数为任何类型,并产生与第二个操作数相同类型的结果。
在Javascript中,&&
运算符返回第一个操作数(如果它是假的),否则返回第二个操作数(see 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
,String
和{{ 1}},分别。
我错过了什么吗?是否有充分的理由使Boolean
表达式的类型与第二个操作数的类型匹配?结果类型不应该像&&
运算符一样,并返回两个操作数的最佳公共类型,如果没有最佳公共类型,则返回||
吗?
答案 0 :(得分:23)
长话短说,这里没有解决方案让所有人满意。
考虑这个常见的习语:
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
}
放弃并决定'地址'是'任何'是非常蹩脚的,因为客户和地址之间没有最佳的共同类型。
在大多数情况下&&使用运算符,已匹配类型,或&&正在以如上所述的价值合并方式使用。在任何一种情况下,返回右操作数的类型都会为用户提供预期的类型。
虽然此时类型安全在技术上已经崩溃,但它不会以可能导致错误的方式执行此操作。您要么测试结果值的真实性(在这种情况下类型或多或少不相关),或者您将使用假定的右操作数进行某些操作(上面的示例同时执行这两个操作)。
如果我们查看你列出的例子并假装左操作数是不确定的truthy或falsy然后尝试编写将对返回值进行操作的合理代码,它会变得更加清晰 - 你可以 与'false&& {}'尚未进入'任何'参数位置或真实性测试。
<强>附录强>
由于有些人不相信上述内容,所以这里有不同的解释。
让我们暂时假装TypeScript类型系统添加了三种新类型:Truthy<T>
,Falsy<T>
和Maybe<T>
,表示T
类型的可能的真值/假值。这些类型的规则如下:
Truthy<T>
的行为与T
Falsy<T>
Maybe<T>
的表达式,当用作if
块中的条件时,将成为同一Truthy<T>
块的主体中的if
和{{ 1 {}在Falsy<T>
块这可以让你做这样的事情:
else
到目前为止相当不错。现在我们可以弄清楚&amp;&amp ;;的类型规则是什么。操作
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>
类型来复制类型系统,因为适合您所需的所有规范的类型已经存在。
这有点像给某人一个盒子并说“这可能是一个空盒子的垃圾,或者是一整箱可回收物品”。您可以安全地将盒子内容物清空到回收站中。
答案 1 :(得分:1)
没有维护语言规范,在这种情况下是错误的。 &&
运算符的结果类型是右侧的类型和左侧的假值的并集。
来自TypeScript 2.0 release notes:
// Compiled with --strictNullChecks
declare function f(x: number): string;
let x: number | null | undefined;
// ..
let b = x && f(x); // Type of b is string | 0 | null | undefined