Flowはnullに対するチェックが厳しく、nullを想定していない場所にnullを渡したり、nullが渡される可能性があったりすると、エラーを出してくれる。
例えば以下のコードでFlowを実行すると、エラーが出る。
// @flow type Owner = { name: string, age: number, }; type Repository = { id: number, isPublic: boolean, owner: Owner | null, }; function showOwnerName(owner) { console.log(`This owner is ${owner.name}.`); } function showRepositoryData(repository: Repository) { console.log(`Id is ${repository.id}.`); console.log(repository.isPublic ? 'This is public.' : 'This is not public.'); showOwnerName(repository.owner); } const exampleRepo = { id: 23, isPublic: true, owner: { name: 'Tom', age: 50, }, }; showRepositoryData(exampleRepo);
このプログラムそのものは問題なく動き、ログが表示される。
まずRepositoryというデータ構造があり、id、isPublic、ownerというデータを持っている。
そしてownerは、nameとageを持っている。
ただし、全てのRepositoryがownerを持っているとは限らず、その値がnullである可能性もある。
この「ownerがnullの可能性がある」というのが、問題になる。
上記のサンプルではownerはnullではないが、型の定義でnullもあり得るとしている以上、プログラム的には、ownerがnullである可能性は否定できない。というか、そういう可能性があるからこそ、owner: Owner | nullと定義しているのだ。
そしてownerがnullのときにowner.nameにアクセスしようとすると、エラーになる。
そのため、上記のコードをFlowでチェックするとエラーになる。
プロパティにアクセスしているけど、そのときにownerがnullである可能性がありますよ、と。
property `name`. Property cannot be accessed on possibly null value
nullチェック
nullかどうかをチェックするようにすれば、エラーは出なくなる。
function showOwnerName(owner) { if (owner) console.log(`This owner is ${owner.name}.`); }
また、仕様上、ownerがnullのときはshowOwnerNameは呼ばれないようになっている、呼ばれてはいけない、というのなら、nullのときは例外を投げるようにするのがいいかもしれない。
function showOwnerName(owner) { if (!owner) throw new Error('owner is null.'); console.log(`This owner is ${owner.name}.`); }
anyへのキャスト
ownerが確実にnullではない、というケースなら、anyにキャストしてしまうという方法もある。
function showOwnerName(owner) { console.log(`This owner is ${((owner: any): Owner).name}.`); }
このように書くことで、ownerの型を好きなもの(上記の場合Owner)にキャストできる。
ただ、公式ドキュメントにThis is unsafe and not recommended.とあるように、型チェックを放棄してしまっているわけで、基本的には使うべきではない。
ただ、こういう書き方も出来ると知っておくと、どこかで役に立つこともあるかもしれない。