TypeScriptでの「!」ってなんなん?
はじめに
開発しているといろんな場所に「!」やら「?」やらが出てきます。
使われる箇所によって当然大きく意味合いが変わってきます。理解できていないまま他のコードを見てなんとなく使っていたので、今回は「!」について整理してみました。
等しくない!...の「!」
不等価演算子。2つのオペランドが等しくないかをチェックし、ブール値の結果を返します。
左右の値が等しくない場合にtrue
を、等しい場合はfalse
を返す演算子です。
const num = 10;
console.log(1 != 1) // false (「1と1って等しくないよね?」 => NO)
console.log(num*5 != 50) // false (「10x5と50って等しくないよね?」 => NO)
否定します!...の「!」
論理否定演算子。真値をとれば偽値になり、偽値をとれば真値になる。
const isVisible = true;
console.log(isVisible); // true
console.log(!isVisible); // false (!を前につけて否定する。)
上記のように!
が付けられたBool値がtrue => false
に、false => true
にする。と思っていたのですがその理解では十分ではないようです。
というのが、正しい理解です。
型キャストというのは、文字列や数値だとしてもBooleanが評価される文脈(たとえばif()
の中とか)ではBooleanとして評価される。ということです。
二重否定「!!」
二重否定なんかもあります。!!true
= !false
= true
です。ぱっと見完全に意味のないコードですよね。ですが、Falsy/Truthyが絡んでくると話は違ってきます・・・
const name = "jojo" // 文字列
console.log(name) // jojo
const isNotEmpty = !!name // Truthy(name) => false(!name) => true(!!name)
console.log(isNotEmpty) // true
- "jojo" : 文字列(
Truthy
) -
false
:!
をつけることで型キャストを行ってその値を反転してfalse
にする。 -
true
: さらに!
をつけてtrue
にする。
といった流れで値を変化させ、undefined
かどうか、0
かどうか、null
かどうかなどをbooleanの値に変換できる便利なやつです。もちろん文字列以外にも配列などでも同じようなことができます。
Falsy/Truthyな値
- Falsyな値は全部で8つです。(
false
、undefined
、null
、NaN
、""
,0
、-0
、0n
) - Truthyな値は上記のfalsyな値以外の全てです。
console.log(false) // false
console.log(!false) // true (false => true に反転)
console.log("false") // true (文字列"false"は truthy)
console.log(!"false") // false (文字列"false"を truthy => false に反転)
console.log(0 == false) // true (0はfalsyな値なので、false == false)
nullじゃない!...の「!」
Non-null assertion operator。OptionalParamaterがnon-nullであるということをコンパイラに明示する。オブジェクトのプロパティに後置で!
をつけることで、null
である可能性を排除して処理を進めることができます。
type Name = {
firstName : string; // firstName は必須
lastName? : string; // lastName はあっても無くてもOK
}
const name = {
firstName : "Joseph",
lastNamae : "Joestar",
}
const isJojo = (name:Name):boolean => {
// firstNameはstring型ということが確定してるからエラーは出ない。
const first = userName.firstName.slice(0,2)
// lastNameはstring型であるとは限らない(undefinedの可能性がある)から・・・
- const last = userName.lastName.slice(0,2) // undefinedの可能性があるのでエラーが出る。
+ const last = userName.lastName!.slice(0,2) // !をつけてundefinedではないことを宣言するとエラーがなくなる。
return first + last === "JoJo"
}
上記の例をみてみると、
Name
の型において、lastName
プロパティはオプショナルであり、undefined
の可能性があります。つまりlastName
の型はstring | undefined
ということです。そのような状態では、
-
string
に対してslice()
を正常に呼び出すことはできますが、 -
undefined
に対してslice()
を呼ぶと、実行時エラーになってしまいます。
それを避けるためにTypeScriptは気をきかせて型エラーを出してくれます。
ただ、「その値は型的にはnull/undefined
な可能性はあるけど、今はnull
でもundefined
でもないんだよ。だからエラーなんて出してくれるな。」と思った時は上記のように、
const last = userName.lastName!.slice(0.2)
と書くことで、TypeScriptは、undefined
である可能性を無視し、string
型として扱ってくれるようになります。
さいごに
とても基本的なことなのだとは思いますが、Falsy/Truthy
とか、non-Null
だとかは、頭の中が整理できてよかったと思います。次は「?」についてまとめるような気がします。
Discussion