誰が読むのかわからんからクッソ冗長に説明してみる。

◆まず

例えば「hoge」というおなまえのオブジェクトがあって、それが「prop」というbooleanなプロパティを持っているときの操作について考える。

let hoge = { prop: true };
if (hoge.prop) console.log('ちばけんま!');

一行目でhogeを作成して、次の行のifにおいてhogeのpropを読みだした。その結果はtrueであるから、consoleに「ちばけんま!」とlogされた。

◆型指定

type(型)というものを定義することが出来る。

例えば「propという真偽値をもつtype」を定義することができる。

type Piyo = { prop: boolean };
let hoge: Piyo = { prop: true };

一行目で「Piyo」というおなまえのtypeを定義した。つづく二行目で「hogeはPiyoというtypeに準拠している」と明示しつつ、hogeを「prop: true」として初期化している。

Piyoに準拠していないものを「=」の右側に書くと、「準拠してないよ」って怒られる。

◆null

「null」は語弊ありありで言うと「空」「なにもない」という意味を表現する。

※以下、nullをundefinedと読み替えていいよ。違う者同士なんだけど。

◆共用体型

「ふたつの型のどっちかに準拠してるよ」ということ。

バーティカルバー「|」で表現される。

以下の例で、hogeは「Piyo型またはnull」に準拠する。

type Piyo = { prop: boolean };
let hoge: Piyo | null = { prop: true }; 

hogeをnullに書き換える例は以下の通り。nullは文脈によって型だったり値だったりする。

type Piyo = { prop: boolean };
let hoge: Piyo | null = { prop: true };
hoge = null;

◆Nullチェック

プログラム外部からの要因により、hogeがPiyoであるかnullであるかの判断が、実行してみるまで分からないという事があり得る。

hogeがnullである場合、nullは当然propというプロパティを持たないわけであるから、propの中身を読もうとしたら例外が発生します。例外が発生って言うのは…良くないことが起きたって事。バグと認識してくれてもいい。

ただ、TypeScriptは賢いので「このhogeってnullになり得るぜ。prop読めないかも知れないぜ。」という注意を実行する前にしてくれるんだ。

以下のコードを書くと「Object is possibly ‘null’.」と注意される。「hogeオブジェクトがnullになるっぽいよ。そういうプログラム書いちゃ駄目だよ。」と教えてくれるのだ。

※太文字の「if (1)」に処理上の意味はない。TypeScriptくんにhogeの内容を予測できなくさせるために書かれている。「1」はTypeScriptにおいてtruthyという性質を持っていて、ifの中ではtrueと同じ扱いをされると思っていい。「if (true)」と書くとTypeScriptくんはhogeの内容が絶対にnullになると理解してしまうから「if (1)」と書いて誤魔化しているだけ。

let hoge: Piyo | null = { prop: true };
if (1) hoge = null;
console.log(hoge.prop);

さて、TypeScriptくんに怒られずに済むにはどうすればいいだろうか。

hogeがnullじゃ無いよというチェックを入れてあげればいい。

let hoge: Piyo | null = { prop: true };
if (1) hoge = null;
if (hoge !== null) console.log(hoge.prop);

「hoge !== null」のifによって、「hogeがnullでない場合」というチェックを通すことができる。nullでないという事は「Piyo」型であるということだ。チェックを通したあとでhoge.propを読んでも絶対に例外が発生することはない。だからTypeScriptくんに怒られない。

◆Optional chaining

だけど、世の中のプログラマーは「いちいちnullの判定を書くのがだるい。オブジェクトがnullだった場合は、プロパティを読まずにそのままnullとして扱ってくれればいい。」と思った。

下記の「hoge?.prop」の「?.」が上記の要望を達成する機能だ。

let hoge: Piyo | null = { prop: true };
if (1) hoge = null;
console.log(hoge?.prop);

上記プログラムを実行するとhogeがnullであるから、propを読まずして「null」とconsoleにlogされる。例外が発生しない。

◆Nullish coalescing operator

「??」というアレがある。(書くの疲れてきた)

下記は「ちばけんま!!!!!」がconsoleにlogされる。

console.log(null ?? 'ちばけんま!!!!!');

「??」は、その左側の値がnullであった場合、右側の値が使用されるという異能をもってますです。

下記は「とらけんま!」がconsoleにlogされる。なぜなら「’とらけんま!’」はnullではないから。

console.log('とらけんま!' ?? 'ちばけんま!!!!!');

null処理のはなしは以上。だいたいわかっただろうか。undefinedも「?.」「??」で捌けるよ。

◆余談:Nullish coalescing operatorの優先順位

はい。この記事を書いた理由。

この記事を書いた理由ではあるんだけど、スゲェ雑に説明する。

このページで「Strict Equality」と「Nullish coalescing operator」の順位を見比べりゃわかるんだが、下記のふたつのconsole.logは異なる出力をする。

let hoge: Piyo | null = { prop: true };
console.log(hoge?.prop ?? false === false); //trueと出力される
console.log((hoge?.prop ?? false) === false); //falseと出力される

なんとなんと、「??」は「===」よりも優先順位が低いんですね。だから「hoge?.prop」が「true」であってもfalseになってくれないんですね。

TypeScriptは基本的にEcmaに実装を合わせている。んだもんでECMAの仕様を漁ったんだけど演算子の優先順位がどこに書かれてんだか分からなかった。

◆結論

そんなかんじ。これ誰向けの記事なんだろう。まぁいいや。