こんにちは。TypeScriptの深淵を覗き込み、日夜コンパイラと対話しているアーキテクトです。
TypeScriptを触っていると、「APIからのレスポンス、このフラグが立っている時だけ中身が変わるんだよなぁ……」という場面に必ず遭遇しますよね。そのたびに `any` を使って型を放棄したり、巨大なユニオン型でコードを汚染したりしていませんか?
今日は、TypeScriptの真骨頂である「条件付き型(Conditional Types)」を使って、APIレスポンスの型を美しく、かつ厳格に動的変換する極意を伝授します。
ここをマスターすれば、あなたの書くコードは「ただ動くだけ」のものから、「コンパイラが論理を保証してくれる」堅牢な資産へと変わります。
—
1. 条件付き型(Conditional Types)とは何か?
一言で言えば、「型レベルのif文」です。
T extends U ? X : Y
これは、「もし型 `T` が型 `U` に代入可能なら `X` に、そうでなければ `Y` になる」というシンプルな構文です。コンパイル時、TypeScriptの型評価エンジンはこの式を読み解き、静的に結果を確定させます。
2. 実践:APIレスポンスをフラグで切り替える
例えば、ユーザーの権限によってプロフィールの詳細データが含まれたり、含まれなかったりするAPIがあるとしましょう。
// 共通のベースレスポンス
interface BaseResponse {
status: number;
}
// 詳細情報
interface UserDetail {
email: string;
lastLogin: Date;
}
// 判定用のフラグによる型定義
type ApiResponse
includeDetail: T;
data: T extends true ? UserDetail : string; // ここが魔法の分岐!
};
このコードの何が凄いのか?
- `T` が `true` なら、`data` は `UserDetail` オブジェクトになります。
- `T` が `false` なら、`data` は単なる `string`(ユーザー名など)になります。
実際に使ってみると、エディタの補完が劇的に変わるのがわかります。
// 1. 詳細が必要な場合
const fullResponse: ApiResponse
status: 200,
includeDetail: true,
data: { email: “dev@example.com”, lastLogin: new Date() } // 型チェックが走る
};
// 2. 詳細が不要な場合
const simpleResponse: ApiResponse
status: 200,
includeDetail: false,
data: “User Name” // 文字列以外を入れるとコンパイルエラー!
};
3. 陥りやすい「罠」と解決策
初学者がよくやってしまうのが、「Genericsの推論ミス」です。
よくある間違い
function getResponse
// … 実装
}
この時、`getResponse(true)` と呼ぶと `ApiResponse
解決策:型ガードの活用
内部で条件分岐を行う際は、`if` 文を使って型を絞り込む(Type Narrowing)のが鉄則です。
function handleResponse
if (res.includeDetail) {
// ここで res.data は自動的に UserDetail に絞り込まれる!
console.log(res.data.email);
} else {
// ここで res.data は string に絞り込まれる
console.log(res.data.toUpperCase());
}
}
4. なぜこの技術が「必須」なのか
フロントエンド開発において、APIの結果を「なんとなくの型」で扱うと、必ずどこかで `undefined` や `null` の参照エラー(Runtime Error)が発生します。
条件付き型を使うということは、「APIの仕様をコードの中に閉じ込める」ということです。バックエンドが仕様を変えた時、型定義を修正すれば、アプリケーション全体で修正が必要な箇所がコンパイラによって即座に可視化されます。
これこそが、TypeScriptを「最強の武器」たらしめている理由です。
—
最後に:TypeScriptの美学
条件付き型は、一見すると複雑に見えるかもしれません。しかし、これは「コンピュータに何を期待しているか」を数学的に記述する行為です。
最初は `T extends true ? X : Y` を書くことに抵抗があるかもしれませんが、一度慣れてしまえば、もう `any` に頼ることはなくなるはずです。
「型はただの制約ではなく、開発者の意思を伝えるドキュメントである」。
この意識を持って、ぜひあなたのプロジェクトにこのパターンを取り入れてみてください。
次回の更新では、さらに踏み込んで「Mapped Types(マップ型)」との組み合わせによる、APIレスポンスの「部分的な更新」について深掘りします。それでは、素晴らしいコーディングライフを!