はじめに
JavaScript、TypeScriptにおいて0がfalseとして判定されること自体は知っていましたが、
空文字も含めるといろいろとややこしかったのでまとめてみます。
間違い等あったらご指摘いただけるとありがたいです。
参考にさせていただいた記事
0はfalseと等価である
JavaScript(TypeScript)において0はfalsyな値であると定義されています。
https://developer.mozilla.org/ja/docs/Glossary/Falsy
偽値 (falsy または falsey) な値とは、論理型コンテキストに現れたときに偽とみなされる値です。
そのため以下のような場合はfalseとなります。
if(0)
if("")
これを知らずにif(value)
で未入力チェックなどをしていると、入力しているのにエラーが発生するぞ!という状況になってしまいます。
こちらに関しては参考記事を見ていただければと思います。
0は許可するけど空文字ははじきたい場合
汎用的な未入力チェックなどで空文字もはじきたい場合、if(value == null)
やif(value == undefined)
ではfalseとなります。
条件を追加する必要がありますが、この場合は少しややこしくなります。
単純にif(value == null || value == "")
にするとまた0がはじかれるようになってしまいます。
空文字""
は等価演算子==
で比較した場合0と等価になります。
オペランドの型が異なる場合は、比較前に同じ型に変換を試みます。
数値と文字列を比較する場合、文字列を数値に変換しようとします。
そしてNumber("")
は0が返却されると定義されています。
空文字列またはホワイトスペースのみの文字列は 0 に変換されます。
具体的な変換プロセス
"" == 0
↓ (空文字列を数値に変換)
Number("") == 0
↓ (Number("")は0を返す)
0 == 0
このことから、等価演算子でははじかれてしまうため厳密等価演算子===
を使用する必要があります。
厳密等価演算子 (===) は、二つのオペランドが等しいことを検査し、論理値で結果を返します。等価演算子とは異なり、厳密等価演算子はオペランドの型が異なる場合、常に異なるものと判断します。
サンプルコード
function test(value){
return value == null || value ===""
}
console.log(test(0))
console.log(test(""))
console.log(test(null))
console.log(test(undefined))
結果
false
true
true
true
TypeScriptで気を付けなくてはいけないこと
TypeScriptで厳密等価演算子を使用する場合はJavaScriptとは違い型を正確に推論します。
そのため0 === ""
はエラーが発生します。
どうしたらええんやという話ですが、関数を使用して引数として値を渡すと暗黙的にany型となるためエラーが発生しなくなります。
function test(value){
return value == null || value === ""
}
console.log(test(0))
console.log(test(""))
console.log(test(null))
console.log(test(undefined))
ただし、anyの使用はできる限り避けたほうが良いです。
型を明示的にした場合は以下のようになります。
function test(value: unknown): boolean {
return value == null || value === "";
}
console.log(test(0))
console.log(test(""))
console.log(test(null))
console.log(test(undefined))
もっといいやり方がある場合は教えていただきたいです。
まとめ
0がfalseなだけであると簡単ですが、空文字やTypScriptの型のあたりが入ってくると少しややこしくなるなと思いました(自分も一回ハマりました)
何と何を比較するとtrueになるのか一覧にしておきます。
等価演算子
0 == "":true
0 == null:false
0 == undefined:false
"" == null:false
"" == undefined:false
null == undefined:true
厳密等価演算子
0 === "":false
0 === null:false
0 === undefined:false
"" === null:false
"" === undefined:false
null === undefined:false