&& 演算子が 2 番目のオペランドの型を生成するのはなぜですか
-
12-12-2019 - |
質問
TypeScript 仕様では、§4.15.6 で、 &&
オペレーター:
&& 演算子は、オペランドを任意の型にすることを許可し、 2 番目のオペランドと同じ型の結果.
JavaScript では、 &&
演算子は、偽の場合は最初のオペランドを返し、そうでない場合は 2 番目のオペランドを返します (ECMA-262 §11.11 を参照).
つまり、左のオペランドが false の場合、 &&
左のオペランドの型に一致する値を返します。例えば、
typeof ( false && {} ) === "boolean" // true
typeof ( '' && 1 ) === "string" // true
typeof ( null && "hello" ) === "object" // true
typeof ( NaN && true ) === "number" // true
Typescript は、上で引用したルールに従って、次のようになります。 間違って 上記の式の型を予測します。 Object
, Number
, String
そして Boolean
, 、 それぞれ。
何かが足りないのでしょうか?の型を作成する十分な理由はありますか? &&
式は 2 番目のオペランドの型と一致しますか?結果の型は次のように動作するべきではないでしょうか ||
演算子を使用し、2 つのオペランドの最も一般的な型を返します。 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
}
Customer と Address の間に最良の共通タイプがないため、あきらめて「address」を「any」と決定するのはかなりダサいでしょう。
&& 演算子が使用されるほとんどの場合、次のいずれかのタイプが使用されます。 すでに match、または && が上記のように値を結合する方法で使用されています。どちらの場合も、右側のオペランドの型を返すと、ユーザーは期待される型を得ることができます。
現時点では型安全性は技術的には機能しませんが、エラーが発生する可能性が高い方法では機能しません。結果の値が真実であるかどうかをテストするか (この場合、型は多かれ少なかれ無関係です)、または何らかの演算に推定右オペランドを使用することになります (上記の例では両方を実行しています)。
あなたがリストした例を見て、左側のオペランドが真であるか偽であるかが不定であるふりをして、戻り値を操作するまともなコードを書いてみると、はるかに明確になります-できることはあまりありません する 「false && {}」は、まだ「任意の」引数の位置または真実性テストに入っていません。
補遺
上記では納得できない人もいたので、別の説明をしておきます。
しばらくの間、TypeScript 型システムに 3 つの新しい型が追加されたと仮定してみましょう。 Truthy<T>
, Falsy<T>
, 、 そして Maybe<T>
, 、タイプの可能な真/偽値を表します。 T
. 。これらのタイプのルールは次のとおりです。
Truthy<T>
まったく同じように動作しますT
- のプロパティにはアクセスできません
Falsy<T>
- 型の式
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
type の偽の値のいずれかになります 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
必要な仕様をすべて満たすタイプがすでに存在するためです。
これは、誰かに箱を渡して、「これはゴミの空の箱か、リサイクル可能な完全な箱のどちらかです」と言うのと少し似ています。箱の中身を安全にリサイクル箱に空にすることができます。