TypeScriptでインスタンスを生成するときに、プロパティの初期値をどうするべきなのか……。最近ずっと気になっていた事柄だったので、考えをまとめてQiitaに投稿しました。
投稿の中で、自分がよく使う初期値の方針をまとめました。
nullnullか0nullnullnull自分の傾向をまとめると、「型の種類を増やしたくないからできるだけnullは使いたくないけど、どうしようもないときはnullを初期値にする。undefinedは本当の未定義と見分けがつかないので初期値としては避ける」ということになります。
nullとundefinedにまつわる指摘と議論この投稿の公開後に早速コメントがあり、nullはよく考えてから使ったほうが良いという指摘と参考記事を紹介されました。
提示されたGitHub Issueで話題になっていた問い掛けは「JavaScriptのユーザーランドではnullを廃止してundefinedに統一するべき」というものでした。
スレッドの中で明確な結論は出ていませんでしたが、nullの利用について肯定・否定の両派から意見が寄せられていました。
nullを肯定する意見
nullを利用しているnullとundefinedは意味が違うので、使い分ければよい。nullにはundefinedより明示的に値が存在しないという意味があるので、その意味で使うべきnullは表現できるが、undefiendは表現できないnullに否定的な意見
nullを使う仕様は変えられないが、ユーザーランドは別nullとundefinedが両方存在している現状が間違っているし、誰もちゃんと使い分けを知らない(だからundefinedに寄せるべき)undefinedを扱う代替手段はどうとでもできるnullを使う場合には意図を明確にするべき他言語の経験がなくWebデザインの延長で開発をやるようになった自分にとって、この議論は興味深かったです。
僕にとってJavaScriptにnullとundefinedが存在するという仕様は当然なことで、そこに疑問を持ったことはありませんでした。
その仕様には何か特別な理由があり、自分が知らないだけで上級者はちゃんと使い分けているものだと思っていたのですが……。
似たような概念が2種類もあることでJavaScriptとTypeScriptの世界に無駄な混乱を招いているということは事実なようです。
確かに、使い分ける理由がないのであれば、寄せられる方に統一するべきでしょう。寄せるのであれば、nullよりもundefinedの方がより一般的なので適当です。
一方で、既存のAPIの仕様がある以上絶対にnullを無くすこともできません。
結局寄せ切ることはできませんが「nullの利用は明確な意図がない限りは最小限にするべき」という程度のことは言えるかもしれません。
undefinedだけを使うnullを使うのであれば利用意図を明確にするnullは甘受するさて、冒頭のプロパティ初期値の話題に戻ったとき、
型の種類を増やしたくないからできるだけnullは使いたくないけど、どうしようもないときはnullを初期値にする。undefinedは本当の未定義と見分けがつかないので初期値としては避ける。
という理由付けが妥当なのかをもう一度考えてみます。
仮に初期値としてundefinedを代入したときに、本当に存在しないプロパティなのかどうかはhasOwnPropertyで調べることができます。
しかしTypeScriptでundefinedを許容する型定義をすると、コンストラクタ内でプロパティへの代入をせずにクラスを実装できてしまいます。
クラスでの実装時には、どちらの型定義でもプロパティへの代入を省略できてしまう
オプショナル型とundefinedとのユニオン型は、オブジェクトとクラスで挙動が違った - Qiita
つまり、undefinedを許容する型定義ではプロパティの存在を保証できません。
それを保証したければ、コンストラクタ内でプロパティにundefinedを代入する運用が必要です。コンパイラが見てくれないのでちょっと面倒そうです。
class MyClass {
public hoge: string | undefined;
constructor() {
// 書かなくてもコンパイルは通るが、省略するとhasOwnPropertyで区別できなくなる
this.hoge = undefined;
}
}
しかし、当初のnullを使う理由であった「本当にプロパティ未定義な状態と、値がない状態を区別できる」という機能が実際に必要な状況がどれだけあるでしょうか?
経験上、それが本当に必要だったシーンはこれまでありませんでした。また、その機能が必要な状況を思いつくことも自分には難しいです。
オブジェクトのプロパティを走査するような機能には関係しそうですが、たとえばディープコピーするときにundefinedなプロパティが律儀に複製されても、そんなに嬉しい状況がなさそうです。
理由が思いつかないのであれば、やはりnullにこだわる意義はないかもしれません……。
nullを使いたいですか?最後に、例のIssueを立てた人がTwitterで行っているnullとundefinedにまつわるアンケートを転載しました。あなたはどちら派でしょうか?
If you don't want to comment in that thread. Vote instead. But read the arguments for dropping `null` first.
— Sindre Sorhus (@sindresorhus) April 7, 2019
TypeScript公式リポジトリのWikiにnullを使ってはいけないという記述を見つけましたが、これはコンパイラの開発者向けガイドであり、TypeScriptそれ自体のためのガイドではありません。
STOP READING IMMEDIATELY THIS PAGE PROBABLY DOES NOT PERTAIN TO YOU These are Coding Guidelines for Contributors to TypeScript This is NOT a prescriptive guideline for the TypeScript community
Coding guidelines · microsoft/TypeScript Wiki
※投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。