TypeScript Type Guardでユニオン型を安全に絞り込む - isキーワード活用法

問題

APIレスポンスが成功・失敗の2つの型のユニオンで返ってくる場合、if文の中で型が絞り込まれず、毎回型アサーションを書かなければならない状況が発生します。

type SuccessResponse = { status: 'ok'; data: string[] };
type ErrorResponse = { status: 'error'; message: string };
type ApiResponse = SuccessResponse | ErrorResponse;

function handle(res: ApiResponse) {
  // res.dataにアクセスできない - 型が絞り込まれていない
}

解決方法

isキーワードを使ったカスタムType Guard関数を作成します。

function isSuccess(res: ApiResponse): res is SuccessResponse {
  return res.status === 'ok';
}

function handle(res: ApiResponse) {
  if (isSuccess(res)) {
    // ここではresがSuccessResponseに絞り込まれます
    console.log(res.data);
  } else {
    // ここではresがErrorResponseになります
    console.log(res.message);
  }
}

配列のフィルタリングでも便利です。

const results: (string | null)[] = ['a', null, 'b', null];

// filterの後も(string | null)[]型のまま...
const bad = results.filter(x => x !== null);

// Type Guardでstring[]に絞り込み
const good = results.filter((x): x is string => x !== null);

ポイント

  • isキーワードは戻り値の型の位置に書き、関数がtrueを返すとその型に絞り込まれます
  • Array.filterにType Guardを渡すと、結果の配列の型が自動的に絞り込まれます
  • typeofin演算子では対応できない複雑な型分岐で特に役立ちます