TypeScript 5.6の"Disallowed Nullish and Truthy Checks"
TypeScript 5.6に入る新機能、Disallowed Nullish and Truthy Checksが気になったので少し手を動かして調べてみました。心の中にしまっておくのも勿体無いので皆さんに共有しておきます。
以下はまとめですが、nullishの扱いについてはほとんど同じ話の繰り返しになるので本記事では触れません。
- 構文的にtruthyだとわかる値を条件節に入れるとエラーになる
- 同じく構文的にnullishでないわかる値を
??
の左辺に渡すとエラーになる - あくまで構文上の情報しか使っていないので、型情報は使っていないので変数に入れて渡すと通る
- falsyな値についても同様のチェックが入る
本題
truthy/falsyのおさらい
JavaScriptにはtruthy/falsyという概念があります。どんな値も、if
やwhile
などの条件節に与えるとtrue
かfalse
に変換されます。true
に変換される値をtruthy、false
に変換される値をfalsyと呼びます。
問題
どんな正規表現もtruthyなので、以下のif
のボディは常に実行されてしまいます。
if (/0x[0-9a-f]/) {
// something to do
}
実装者はもしかしたらtest
メソッドを使い忘れたのかも知れませんが、これまでのTypeScriptコンパイラーはこのコードを通すので、実装者は実行するまでこの事実に気づけませんでした。
他にも、関数はtruthyなので、<=
を=>
にタイポして関数にしてしまうとやはりif
が常に実行されてしまいますが、コンパイル時には気づけません。
しかし、TypeScript 5.6からは上記のコードはコンパイル時にエラーになります。コンパイラは/0x[0-9a-f]/
が正規表現であることを構文から理解できるので、その情報を元に「こいつはいつもtruthyだよ」とエラーを出してくれます。
変数に入れて渡すと通る
注意点として、あくまで構文しか見ていないので変数に入れて渡すとエラーになりません。
const regex = /0x[0-9a-f]/
if (regex) {}
TypeScriptにはRegExp
型があるのでエラーにしてくれるかと思いきや、構文からは判断できないのでエラーになりません。
また、配列もtruthyなのでif ([]) {}
はエラーになりますが、
const arr = []
if (arr) {}
は通ります。
例外として、関数は変数に入れてもエラーになります。
if (x => 0) {} // error
const f = (x: number) => 0
if (f) {} // error
ただ、if (f) {}
はこれまでのバージョンでもエラーだったようです。エラーメッセージはThis condition will always return true since this function is always defined. Did you mean to call it instead?(2774)
となっており、今回導入されたエラーとはコードが違います(これは2774, 今回導入されたのは2872)。他方、if (x => 0) {}
のエラーコードはちゃんと2872になっています。
ちなみに、アナウンスではtruthyしかチェックしないかのようなタイトルになっていましたが、falsyに対しても同様のチェックが入るようで、例えばif (undefined) {}
もエラーになりました。
今回紹介しなかったnullishチェックの方も同様の性質を持っています。あまりハマる人もいないかも知れませんが念の為の注意喚起でした。
最後にplaygroundを置いておきます。ではでは
Discussion