記事の趣旨
TypeScriptには、値がnullでないことを示すための、非nullアサーション演算子(Non-Null Assertion Operator) !
という構文があります。
これが、便利ですがあまり知られていないような気がしたので(自分も最近知りました)、使用例や ?
との違いをまとめました。
使用例
前提
例として、あるinput要素が存在することが保証されていて、その要素にフォーカスしたい場合を考えます。
この時以下のように書くと型エラーが発生します。
document.getElementById('input').focus() // エラー: オブジェクトは 'null' である可能性があります。
これは、 document.getElementById
の戻り値が HTMLElement | null
となるためです。
オプショナルチェイニングの注意点
要素が存在する(nullでない)ことが保証されている場合、それをコンパイラに伝える必要がありますが、その時以下のようにオプショナルチェイニング ?
を使いたくなるかもしれません(エディタによってはそのように補完してくれます)。
document.getElementById('input')?.focus()
こうすると一旦エラーは解消されますが、万が一改修ミスによってinput要素のidが変わった場合、コンパイルエラーも実行時エラーも発生せず、フォーカスの動作が行われないという発見しづらいバグを生む可能性があります。
→ 型エラーを防ぐ目的で、安易に ?
を使わないように注意が必要。
非nullアサーション演算子
上記の問題を防ぐ方法として、以下のように非nullアサーション演算子 !
を使う方法があります。
document.getElementById('input')!.focus()
!
は、オペランドが非nullかつ非undefinedであることをassertするものです。これは、以下のように明示的にassertすることを省略した書き方とも言えます。
(document.getElementById('input') as HTMLElement).focus()
このように書くことで、input要素が取得できなくなった場合は、 Cannot read property 'focus' of null
という実行時エラーが発生するため、バグに気付きやすくなります。
ちなみに、!
は、後ろにメソッド等が続く必要がある訳ではありません。( ?
の場合は必須)
const inputElement = document.getElementById('input')!
不適切に利用しない
あくまで上記の例は、要素が存在していることが保証されている場合の使用例です。
eslintの typescript-eslint/recommended
のpluginで、 no-non-null-assertion
というルールが設定されていることからも分かるように、不適切な箇所に使用しないように注意する必要があります。
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-non-null-assertion.md
参考
TypeScript Deep Dive
https://typescript-jp.gitbook.io/deep-dive/intro/strictnullchecks