読み込み状態を複数の真偽値で持つと、isLoading: trueかつhasError: trueという組み合わせも表せてしまいます。状態を一つのstatusにまとめる例です。
type LoadState<T> =
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; message: string };
function getTitle(state: LoadState<{ title: string }>): string {
if (state.status === 'success') {
return state.data.title;
}
return '';
}
successの分岐ではdataを使えます。loadingとerrorにはdataを定義していないので、分岐せずに読むと型エラーになります。
データがある状態にだけ持たせる
data?: Tとして全状態に置くと、成功時にもundefinedの確認が必要です。この型では、成功した状態とデータの存在を一緒に定義しています。
このような共通のプロパティで型を絞り込む書き方は、TypeScript HandbookのDiscriminated unionsに説明があります。