TypeScriptでタグ付きユニオン型(Discriminated Union)を定義する方法
生徒
「TypeScriptでユニオン型を使うと便利だと聞きました。でも、種類が増えるとどれがどのデータか分からなくなってしまいませんか?」
先生
「確かに、ただのユニオン型だけだと判別が難しくなることがあります。そこで役に立つのが、タグ付きユニオン型(Discriminated Union)です。」
生徒
「タグ付きユニオン型って、どういう仕組みなんですか?」
先生
「それは、データの種類を表す“目印(タグ)”をつける方法です。このタグを使うとTypeScriptが正確に型を判定できるので、安全で分かりやすいコードになります。」
1. タグ付きユニオン型とは?
タグ付きユニオン型(Discriminated Union)は、TypeScriptで複数の型をひとつにまとめて扱うための仕組みで、各型の中に種類を示すための共通プロパティ(タグ)を持たせる方法です。 ユニオン型は便利ですが、種類が増えるとどのデータがどの型に属しているのか判別しにくい場面が出てきます。そこでタグをつけて、TypeScriptに「これはこの型ですよ」と伝えることで、より安全な型チェックができるようになります。
例えば、「四角形」と「丸」のように形の種類ごとに異なるデータを扱うとき、タグをつければプログラムが誤解せずに正しい処理を選べます。これは現実で荷物に「割れ物注意」や「食品」などのラベルを貼るのに似ています。
2. タグ付きユニオン型を定義する基本構文
まずは基本的な定義方法を見ていきます。タグとは、typeやkindなどの固定された文字列を入れておくプロパティのことです。これを使うことで、どの型かを簡単に判別できます。
type Square = {
kind: "square";
size: number;
};
type Circle = {
kind: "circle";
radius: number;
};
type Shape = Square | Circle;
この例では、四角形は kind が "square"、円は kind が "circle"というタグを持っています。これによって、Shape型の値を扱う際にタグを見ればどの形か判断できます。
3. タグを使って安全に分岐する方法
タグ付きユニオン型が特に力を発揮するのは、switch文やif文で型を分岐するときです。タグを条件にすることで、TypeScriptが自動的に「今このブロックでは Square だな」などと推論してくれます。
function getArea(shape: Shape): number {
switch (shape.kind) {
case "square":
return shape.size * shape.size;
case "circle":
return shape.radius * shape.radius * Math.PI;
}
}
shape.kind を参照することで確実に分岐でき、誤って別の型のプロパティを読んだり、未定義の値を参照したりするミスを防げます。
4. タグ付きユニオン型が便利な理由
タグ付きユニオン型が多くの開発で使われる理由はいくつかあります。
- 型推論が正確になるため、エラーを事前に防げる。
- コードを読む人がすぐにデータの種類を理解できる。
- 種類が増えても安全に処理を追加できる。
特に規模の大きいアプリや複数人で作業するプロジェクトでは、データの種類ごとに明確なタグをつけることでトラブルが大幅に減ります。これは整理された引き出しにラベルを貼るようなもので、欲しい情報を素早く正確に取り出すことができます。
5. タグの名前は何でもOK
タグに使うプロパティ名は「kind」だけでなく、「type」「tag」「category」など自由に決められます。ただし、各データ構造が共通のプロパティ名を持つ必要があるため、プロジェクト内で統一しておくことが大切です。
また、タグに使う文字列はリテラル型として扱われるため、スペルミスをするとすぐにエラーが表示されます。これも安全なプログラミングにつながるポイントです。
6. 実務での利用シーン
タグ付きユニオン型は、実務でも非常に多くの場面で使われます。例えば次のようなケースです。
- APIのレスポンスが複数のパターンを持つとき
- UIの部品が種類ごとに違う設定を持つとき
- ゲームやシミュレーションでキャラクターの種類を分けるとき
これらはどれも、種類ごとに異なるデータ構造を扱う典型的な例です。タグがあることで確実に正しい処理を選べるため、プログラムが安定して動きます。
まとめ
TypeScriptで扱うタグ付きユニオン型は、種類の違うデータをひとつのまとまりとして安全に管理できるとても強力な仕組みです。とくに、複雑な処理や複数のパターンが存在するアプリケーションでは、タグをつけることで「このデータはどの型なのか」を確実に識別できるため、バグを減らし、読みやすいコードを保ちやすくなります。タグという目印のおかげで、プログラムが自動的に型を推論して間違いを防いでくれるので、開発者は安心して処理を書くことができます。
また、タグ付きユニオン型は「種類の追加にも強い」構造であり、あとから新しいパターンを増やしたいときも扱いやすい特徴があります。データが増えるほど複雑になりがちな場面でも、タグという共通プロパティがあることで十分に整理された形で拡張できます。これは、小分けされた引き出しにはっきりしたラベルを貼って並べておくようなもので、あとから探したい情報にすぐたどり着ける安心感があります。
ここまでの内容を振り返ると、タグ付きユニオン型は単なる構文ではなく、アプリ全体の安全性や見通しの良さに直接つながる重要な設計手法だということが分かります。複雑なデータ管理を行う現場でも、日常的に使われる理由がよく理解できたのではないでしょうか。特に実務では、APIレスポンスやUIの状態管理など、さまざまな場面で活用できるため、TypeScriptを扱うなら知っておく価値の高い知識です。
簡単なサンプルで振り返り
最後に、タグ付きユニオン型のポイントを再確認できるサンプルコードを載せておきます。
type Success = {
status: "success";
data: string;
};
type Error = {
status: "error";
message: string;
};
type Result = Success | Error;
function handleResult(result: Result) {
switch (result.status) {
case "success":
console.log("成功:", result.data);
break;
case "error":
console.log("エラー:", result.message);
break;
}
}
この例では「status」というタグを使用し、成功とエラーを明確に区別しています。タグのおかげでTypeScriptが安全に型を判断し、適切な処理をスムーズに実行できます。実務でもよく使われる形なので、ぜひ覚えておきたいポイントです。
生徒
「最初はユニオン型って便利だけど複雑な印象がありました。でもタグがあると一気に分かりやすくなりますね!」
先生
「そうですね。タグがあるだけで型の判別が正確になり、コードが読みやすく安全になります。大規模な開発では特に役立つ考え方ですよ。」
生徒
「switch文で分岐する時に、TypeScriptが自動的に型を推論してくれるのも驚きでした!誤ったプロパティにアクセスしなくて済むのがすごく安心です。」
先生
「その通りです。タグ付きユニオン型を使うとミスが起きにくくなり、処理の追加にも強い構造になります。ぜひ普段の開発でも活用してみてください。」
生徒
「今日学んだことを使えば、TypeScriptの型設計がもっと上手くできそうです。ありがとうございます!」