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.
とあるように、型チェックを放棄してしまっているわけで、基本的には使うべきではない。
ただ、こういう書き方も出来ると知っておくと、どこかで役に立つこともあるかもしれない。