TypeScriptでPromise<T>な戻り値でnullが返ってくる問題について
最近TypeScriptでサーバサイドの実装をしている。
特に問題なく快適にかけているが、やっぱりハマるところがある。
それは「Promiseな戻り値でnullが返ってくる」という問題。
何が起きたのか?
Fireormを使ってfirebaseのCloud Firestoreからデータを取得しようと以下のようなコードを書いた。
|
|
このときに疑問に思ったのはfindById
で存在しないIDを指定したらどのような挙動をするのか?
自分は「Promiseで戻り値が保証されているのでErrorがthrowされる」のかなと思った。しかし違った。
返ってきたのはそう「null」だった。
Javaの場合は「戻り値型を指定してのnullを返すこと」ができる。
|
|
しかし同じようなコードをTypeScriptで書くと普通はコンパイルエラーになる。
|
|
Fireormのrepository.findByIdから戻された値はnullだったのだ…。
Fireormの実装について
FireormのAbstractFirestoreRepositoryの実装箇所を見ると明らかだが、doc.existsじゃない場合にreturn null
を実装している箇所がある。
これはなぜコンパイルエラーにならないのか?
strictNullChecksオプションについて
https://typescript-jp.gitbook.io/deep-dive/intro/strictnullchecks
strictNullChecksをtrueにすると、コンパイル時にコンパイル時にnullエラーが発生するが、そうじゃないとランタイム時にエラーが発生する。
なので return null
なコードも実行時にエラーになるというか、実行時はjsなわけでエラーにならないと…。
Fireormが return null
していてもコンパイルエラーにならないのは strictNullChecks
が true
ではないからということかと思います。
ためしにコードを落としてきて、tsconfigでstrictNullChecks: true
にしてビルドするとエラーになる。
手元のプロジェクトで strictNullChecksを有効にしなくても returen nullがエラーになる
手元にあるプロジェクトで 戻り地の型指定しながらreturn null
なコードを書いたらエラーになった。
しかしstrictNullChecks
は指定していない。
なぜだろう?
tsconfig.jsにはstrict: true
と記載があるため、エラーになっていた。
strict: true
を指定すると何が起きるのか?
https://www.typescriptlang.org/docs/handbook/compiler-options.html
Enabling —strict enables —noImplicitAny, —noImplicitThis, —alwaysStrict, —strictBindCallApply, —strictNullChecks, —strictFunctionTypes and —strictPropertyInitialization.
ということらしい。
つまりstrictNullChecks
は有効になっている。なので、エラーになるということ。
まとめ
- 戻り値の型が指定されていていも、tsconfigの状況によってはnullを返す
- TypeScriptな他のライブラリを使うときは
strict
orstrictNullChecks
のオプションがどうなっているかを見てる
最後に
strictNullChecksを教えていただいた@_sunnyoneさんありがとうございました。
strictについて教えていただいた@nanopx大先生ありがとうございました。