TypeScriptで値なしをundefinedに統一する
主張
- 値なしをundefinedに統一すること
- なぜ統一するか?
- なぜnullに統一しないのか?
- APIのレスポンスやライブラリ、またはjsのAPIでnullが発生しうるが、それにはどう対応すれば良いか?
- 値なしのハンドリングを論理否定演算子(
!
)で行うこと- なぜ
x === undefined
としないのか? - null/undefinedと同様に0/空文字もtrue判定となるが、、、
- なぜ
目的
TypeScript/JavaScriptにおいて、nullを可能な限り使用せず、undefined/optionalの使用を勧める、もしくはコーディング規約に追加すること。
undefinedとnullの使い分けを回避することで、余計な考え事を減らし、アプリケーション開発に集中すること。
対象
フロントエンドにおける主張です。
バックエンドについてはDBなどが関わってくるため、対象外。nullableなカラム定義などに対応するなどは考えると厄介なため。
前提
そもそもundefinedとnullはどう違うか
undefined | null | |
---|---|---|
EcmaScriptの定義 | primitive value used when a variable has not been assigned a value = 変数に値が代入されていない時のプリミティブ値 |
primitive value that represents the intentional absence of any object value = 意図した欠損を表すプリミティブ値 |
自然発生の有無 | 自然発生する | 自然発生しない |
統一のしやすさ | 統一しやすい | undefinedが自然発生するため、統一しづらい |
値なしをundefinedに統一すること
なぜ統一するのか
- 意味合いの違いを理解して使い分けることがそもそも難しいため。
- 「各ケースでundefinedとnullどちらを使うべきか」という共通認識を作ることが困難なため。
- 使い分けたときに見合うメリットが少ないため。
なぜnullに統一しないのか
- 前項でも触れたように、nullは自然発生しないが、自然発生するundefinedに統一した方が楽なため。
APIのレスポンスやライブラリ、またはjsのAPIでnullが発生しうるが、それにはどう対応すれば良いか?
以下、2案がある。
案1. それぞれでnullをundefinedに変換する処理を挟む。
案2. 実態はnullでも型の上ではundefinedであることを許容する。そして値なしのハンドリングを論理否定演算子などを用いて行う。
!
)で行うこと
値なしのハンドリングを論理否定演算子(
x === undefined
としないのか?
なぜ 前項の「APIのレスポンスやライブラリ、またはjsのAPIでnullが発生しうるが、それにはどう対応すれば良いか?」の案2を採用する場合に採用したいルール。falsyな値を同じ扱いにすることで、実行時のnullとundefinedの違いを許容できる。
また
if(x === undefined){
// do something
}
とするよりも
if(!x){
// do something
}
短くコードを記述可能である。特に以下のように条件が増えた際などにはかなり有効でコード全体の可読性の向上やアプリケーションのロジックに集中できる。
// before
if(x === undefined && y === undefined && z === undefined){
// do something
}
// after
if(!x && !y && !z){
// do something
}
null/undefinedと同様に0/空文字もtrue判定となるが、、、
確かにxに0もしくは''
(空文字)が代入されている場合には、!x
はtrueとなり、undefinedと0の区別ができない
といった問題が生じることもある。しかし、そもそも0とundefinedで意味合いの違いが発生しているロジックはプログラムとして適切かと言われると多くの場合はそうではないと考える。そもそもその区別ができないケースでは、インターフェースの設計に戻るか、もしくは例外的に0や空文字のハンドリングをするのが適切ではないかと考える。というかそのような考えもとにしてをコーディング規約を設定することでコードの統一感を図る。
参考
Discussion