TypeScript仕様では、§4.15.6で&&
演算子について次のように述べています。
&&演算子を使用すると、オペランドを任意の型にすることができ、2番目のオペランドと同じ型の結果が生成されます。
Javascriptでは、&&
演算子は、偽の場合は最初のオペランドを返し、それ以外の場合は2番目のオペランドを返します( 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
と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」と決定するのはかなり難しいでしょう。
&&演算子が使用されるほとんどの場合、タイプalreadyが一致するか、&&が上記のような値の合体方法で使用されています。いずれの場合も、右のオペランドの型を返すと、ユーザーは期待される型になります。
型安全性はこの時点で技術的に故障していますが、エラーが発生する可能性のある方法では故障していません。結果の値の真偽をテストするか(この場合、型は多かれ少なかれ無関係です)、または何らかの操作に推定右オペランドを使用します(上記の例では両方を実行します)。
あなたがリストした例を見て、左のオペランドが不確定に真実または偽であると偽って、戻り値を操作する正気のコードを書き込もうとすると、それははるかに明確になります-できることはあまりありませんdowith'false && {} 'は、まだ' any '引数位置または真正性テストに入っていません。
補遺
上記に納得できない方もいらっしゃるので、別の説明をさせていただきます。
TypeScript型システムが3つの新しい型を追加したとしましょう:Truthy<T>
、Falsy<T>
、およびMaybe<T>
は、タイプT
の可能な真偽の値を表します。これらのタイプのルールは次のとおりです。
Truthy<T>
はT
とまったく同じように動作しますFalsy<T>
のプロパティにはアクセスできませんMaybe<T>
の式は、if
ブロックの条件として使用されると、同じif
ブロックの本体ではTruthy<T>
になり、else
ブロックではFalsy<T>
になります。これにより、次のようなことができます。
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
テストで使用する場合は、そのif
ステートメントのブロックでTruthy<U>
になるはずです。言い換えれば、Falsy<T> XOR Maybe<U>
isMaybe<U>
。それはすべて同じルールに従います。必要なすべての仕様に適合する型がすでに存在するため、この奇妙なXOR
型を追加することにより、ここで型システムを複雑にする必要はまったくありません。
これは、誰かに箱を渡して「これはゴミの空の箱か、リサイクル可能な箱一杯のどちらかです」と言うのと少し似ています。ボックスの中身を安全にごみ箱に入れることができます。