TypeScriptのstrictNullChecksを有効化して機能を実装したときの効果を確認した

一昨日「記事リストを10件ごと分割して表示する」機能を実装した例を紹介しました。そのコードを昨日、noImplicitAnyオプション(暗黙的なany型を許容しない)・strictNullChecksオプション(全ての型でnullundefinedを禁止)を有効にして書き換えてみました。書き換えたコードは記事を更新して公開しているのですが、書き換えた効果の程はいかに?と思い実際に挙動を確認してみました。

よくあるのは想定と違うHTMLになっていたとか、実装した機能を利用するページ以外でも機能が実行されたとかで要素が取得できずエラーになるケースでしょうか。開発者ツールのコンソールにエラーが出ているのはよく目にします。自分の案件ではそのようなことがないよう確認していますが、少々手間のかかる作業かもしれませんし予想できなければ見逃してしまうかもしれません。
画面キャプチャ:「Cannot read property 'querySelectorAll' of null」のエラーが表示されたコンソール

strictNullChecksオプションを有効にした場合、ID属性値を元にある要素を取得しさらにquerySelectorAll()で要素を取得するコードは以下のように記述します。

const elem: HTMLElement | null = document.getElementById(id);
const list: Array<HTMLLIElement> = Array.from(elem?.querySelectorAll('[some query]') ?? []);
  • nullが入る可能性がある変数には型を記述するときに| nullを追記
  • nullが入っているかもしれない変数を利用するときに?演算子を利用

私はSwiftでコーディングをした経験があってオプショナル型はしっかり学習したので、この記述は容易に理解できました。書き換えたコードを実行すると期待通り開発者ツールのコンソールにエラーが出ることはなくなりました。strictNullChecksオプションが有効の時、処理の返値がnullになる可能性があるのに| nullが書かれていない部分等はコンパイル時にエラーになるので、開発者ツールにエラーが表示されるようなコードはほぼ排除できそうです。(この変数も| null| undefinedが必要なのでは?というケースが1箇所ありました。)

コンパイルされたコードはどのようになっているのだろうと確認してみると、しっかりnullであるか否かのチェックが入っていました。(thisが入っているのは一昨日のブログ記事に掲載のコードを変換しているためです。)これが?演算子1つで書けるのはとても助かります。

list = Array.from((_b = (_a = this.elem) === null || _a === void 0 ? void 0 : _a.querySelectorAll(this.options.listItemQuery)) !== null && _b !== void 0 ? _b : []);

Web APIの返値は読みやすいところではMDNに書かれています。例えばDocument.getElementById()です。

指定された ID に一致する DOM 要素オブジェクトを記述した Element オブジェクト、または文書内に一致する要素がなければ null です。

TypeScriptのnoImplicitAnyオプション・strictNullChecksオプションを有効活用して、より品質の高いコードを書いていきたいと考えました。