【入門編】 Conditional Typesの基本構造 (T extends U ? X : Y) – TypeScript実践ガイド

こんにちは!TypeScriptの世界へようこそ。チーフアーキテクトの私です。

毎日フロントエンドのコードを書いていると、「あ、これさっき書いたやつと同じ型だけど、少しだけ条件によって変えたいな……」なんてモヤモヤする瞬間、ありませんか?

「TypeScriptの型定義って、なんだかカチコチに固まっていて融通が利かないなぁ」なんて感じているあなた。大丈夫です、安心してください。今日ご紹介する「Conditional Types(条件付き型)」を使えば、その悩みは一気に吹き飛びます!

今回は、型レベルの「もしも(三項演算子)」であるこの強力な武器について、身近な例えを交えながら、一緒にやさしく紐解いていきましょう。

—

1. そもそも Conditional Types(条件付き型)ってなぁに?

いきなり難しいコードを見るのはお腹いっぱいになっちゃうと思うので、まずは私たちの身近な「自動販売機」を思い浮かべてみてください。

自動販売機のボタンを押すとき、私たちはこう考えますよね。

  • 「もし」 100円玉を入れたら 「なら」 ジュースが出る 「さもなくば」 エラーになる

Conditional Typesというのは、まさにこの「もし〜ならA、違えばB」という分岐(三項演算子)を、TypeScriptの『型』の世界で行う仕組みのことです。

基本の形はこう書きます。

T extends U ? X : Y

「うわっ、記号がいっぱい出てきた……」と思いましたか? 大丈夫、分解すれば怖くありません。日本語に翻訳してみましょう。

> 「もし型 `T` が、型 `U` のルールにすっぽり収まる(extendsする)なら `X` という型になり、そうじゃなければ `Y` という型にするよ!」

ね? ただの「型の仕分けルール」なんです。

—

2. 身近な例で感覚を掴もう:「お弁当の仕分け」

では、もう少し身近な例として、「お弁当の仕分けボックス」を想像してみてください。

ここに、なんでも入れられる箱があります。もしその箱に入ってきたのが「お肉」だったら「ガッツリ肉弁当の型」になり、お肉じゃなくて「野菜」だったら「ヘルシー野菜弁当の型」にする……そんな判定を型でやってみましょう。

実際のTypeScriptコードを見てみます。

// 指定された型(T)が string(文字列)かどうかを判定する型を作ります
type IsString = T extends string ? “文字だよ!” : “文字じゃないよ…”;

// 試してみましょう!
type A = IsString<"こんにちは">;
// 結果:「文字だよ!」という型になります

type B = IsString<123>;
// 結果:123は数値なので、「文字じゃないよ…」という型になります

おぉ、なんだか面白くなってきませんでしたか?
`T extends string` の部分で、「ねえ、`T`って `string` の仲間?」とTypeScriptくんが判定し、合っていれば `?` の後ろ(`X`)、違えば `:` の後ろ(`Y`)を返してくれています。

これが、Conditional Typesの基本構造のすべてです。

—

3. 実務でどう使うの? 初学者が感動する実践的な例

「概念は分かったけど、実際のWeb制作やアプリ開発で何の役に立つの?」という声が聞こえてきそうですね。

よくある実務のシーンで考えてみましょう。
例えば、APIからデータを取得する関数を作るとき、「引数に渡すモードによって、返ってくるデータの形が変わる」というケースは本当によくあります。

ここでConditional Typesの出番です!

// 簡易的なAPIの返却値の型を考えてみましょう

// 詳細データが欲しいとき用の型
type DetailedData = {
id: number;
title: string;
description: string; // 詳細には説明文がある!
createdAt: string;
};

// ざっくり一覧データが欲しいとき用の型
type SummaryData = {
id: number;
title: string; // 一覧には説明文はいらないよね
};

// モード(boolean)を受け取って、返すデータの型をパッと切り替える魔法の型
type ApiResponse = T extends true ? DetailedData : SummaryData;

// — さあ、使ってみましょう! —

// パターン1:詳細データが欲しい場合(trueを渡す)
const fetchDetailed: ApiResponse = {
id: 1,
title: “TypeScript入門”,
description: “Conditional Typesについて優しく解説します。”, // 持たせないと怒られます!
createdAt: “2023-10-25”
};

// パターン2:一覧データで十分な場合(falseを渡す)
const fetchSummary: ApiResponse = {
id: 1,
title: “TypeScript入門”,
// description や createdAt がなくても、エラーになりません!
};

どうでしょう? `ApiResponse` と書くだけで、自動的に「詳細データ用の厳しい型」に変化し、`false` と書けば「シンプルな一覧用の型」に変化する。

これが、私たちフロントエンドエンジニアがConditional Typesに恋をする瞬間です。コードの再利用性が爆発的に高まり、型安全なコードがスッキリ書けるようになります。

—

4. つまずきやすいポイント:気をつけること

最後に、初学者の人がここで「あれっ?」とハマりがちなポイントをこっそりシェアしておきますね。

それは、「ジェネリック型(Tなど)がまだ決まっていない状態のときは、条件分岐の結果もすぐに確定しない」ということです。

// 途中経過の関数の中などで使うとき、Tが何者か分からない瞬間があります
function checkType(value: T) {
// ここではまだ T が「何が来るか分からない(プレースホルダー状態)」なので、
// 厳密な判定ができないことがあります。
}

「あれ、さっきみたいにすぐに結果が出ないぞ?」と焦るかもしれませんが、それはTypeScriptくんが「まだ実物を見てないから、判断を保留してるんだよ」と頑張っている証拠です。実際に使うときに型がピタッと決まれば、条件分岐もちゃんと動いてくれますので安心してくださいね。

—

まとめ

いかがでしたでしょうか?
Conditional Types(`T extends U ? X : Y`)は、最初は難しそうな暗号に見えますが、中身はただの「型のための三項演算子(もしもボックス)」です。

1. `T extends U` で「条件」をチェックする
2. `? X` で「合っていればこう!」と決める
3. `: Y` で「違っていればこう!」と決める

この3ステップの型パズルを味方につけると、TypeScriptを書くのがぐっと楽しく、そして誇らしいものになります。

最初は完璧に使いこなせなくても大丈夫。まずは自分のコードの中で「ここ、もし〜なら型を変えられたら楽なのに!」と思う場所を見つけたら、そっとこの魔法の構文を思い出してみてくださいね。

あなたのTypeScriptライフが、より豊かでエラーのないものになりますように。
それでは、次の現場でお会いしましょう!チーフアーキテクトでした。

コメント

タイトルとURLをコピーしました