【TypeScript】Union型とIntersection型の使い分け - 柔軟な型の組み合わせと条件分岐
2024-11-10
2024-11-10
TypeScriptのUnion型とIntersection型とは
TypeScript
では、データに応じて柔軟に型を定義できるユーティリティとしてUnion型とIntersection型が用意されています。これらを使うことで、複数の型を組み合わせて型安全に条件を設定したり、複雑なデータ構造を表現することが可能になります。
Union型は、指定した複数の型のいずれか一つを持つ型を定義し、データの柔軟性を保ちます。一方、Intersection型は指定した複数の型すべてのプロパティやメソッドを持つ型を定義し、より厳密で統合されたデータ構造を実現します。
Union型とは
Union型は、複数の型のいずれか一つを取る型で、どれか一つの型に適合すれば良い場合に使用されます。Union型を利用することで、異なる型の値を安全に扱うことが可能です。
Union型の構文
Union型の構文は、複数の型を縦線(|
)で区切ることで定義します。
type 型名 = 型A | 型B | 型C;
たとえば、文字列または数値を受け入れる変数の型を定義する場合、以下のように記述します。
let value: string | number;
value = "Hello";
value = 42;
この例では、value
は文字列または数値のどちらでも受け入れることができ、型安全が確保されています。
Union型の使用例
Union型は、関数が複数の型の引数を受け入れる場合や、異なる型のデータを操作する必要がある場合に役立ちます。
function formatValue(value: string | number): string {
if (typeof value === "string") {
return `String: ${value}`;
} else {
return `Number: ${value}`;
}
}
console.log(formatValue("Alice")); // 出力: String: Alice
console.log(formatValue(30)); // 出力: Number: 30
この例では、value
が文字列か数値かによって異なるフォーマットを適用しています。TypeScript
はtypeof
による型ガードを利用して、それぞれの条件下で安全に型を推測し処理を行います。
Union型の実践例 - さまざまなAPIレスポンスに対応
Union型は、APIレスポンスが異なるデータ形式を取る場合にも便利です。例えば、エラーレスポンスと成功レスポンスを区別して処理する際に活用できます。
interface SuccessResponse {
data: string;
}
interface ErrorResponse {
error: string;
}
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if ("data" in response) {
console.log("Success:", response.data);
} else {
console.log("Error:", response.error);
}
}
このように、ApiResponse
がSuccessResponse
またはErrorResponse
のどちらかであれば安全に処理が可能です。
Intersection型とは
Intersection型は、複数の型をすべて組み合わせた型で、すべての型のプロパティやメソッドを含むデータを表現します。これにより、異なる型の属性を結合した一つの型を作成でき、複合的なデータ構造を型安全に扱えます。
Intersection型の構文
Intersection型の構文は、複数の型をアンパサンド(&
)で結合することで定義します。
type 型名 = 型A & 型B & 型C;
たとえば、Person
型とContact
型の両方のプロパティを持つ型を定義する場合、以下のように記述します。
interface Person {
name: string;
}
interface Contact {
email: string;
phone: string;
}
type PersonContact = Person & Contact;
const contact: PersonContact = {
name: "Alice",
email: "alice@example.com",
phone: "123-456-7890"
};
この例では、PersonContact
型がPerson
とContact
のすべてのプロパティを持ちます。
Intersection型の使用例
Intersection型は、データに複数の属性が必要な場合に役立ちます。例えば、ユーザー情報と権限情報を組み合わせた型が必要な場合に使用できます。
interface User {
id: number;
name: string;
}
interface Permissions {
isAdmin: boolean;
canEdit: boolean;
}
type AdminUser = User & Permissions;
const admin: AdminUser = {
id: 1,
name: "Bob",
isAdmin: true,
canEdit: true
};
AdminUser
型は、User
型とPermissions
型の両方のプロパティを持つ必要があり、ユーザー情報とその権限が一つに統合されたデータ型として利用できます。
Intersection型の実践例 - 拡張可能な設定データ
Intersection型は、特定の設定項目を組み合わせて拡張する場合にも便利です。例えば、一般的な設定とUIに関する設定を組み合わせて、全体の設定オブジェクトを作成します。
interface GeneralSettings {
appName: string;
version: string;
}
interface UISettings {
theme: "light" | "dark";
showSidebar: boolean;
}
type AppSettings = GeneralSettings & UISettings;
const settings: AppSettings = {
appName: "MyApp",
version: "1.0.0",
theme: "dark",
showSidebar: true
};
このように、AppSettings
型を使ってアプリ全体の設定を一つのデータとして扱うことができます。
Union型とIntersection型の使い分け
Union型とIntersection型は、それぞれ異なる場面で役立ちます。以下は、使い分けのポイントです。
- Union型: 複数の型のうちどれか一つの型であればよい場合に使用します。例えば、関数が異なる型の引数を受け入れるときや、異なるフォーマットのデータに対応するときに利用します。
- Intersection型: 複数の型のすべてのプロパティを含む必要がある場合に使用します。例えば、複数のデータ属性を統合したい場合や、データ構造を拡張したいときに役立ちます。
Union型とIntersection型の組み合わせ
Union型とIntersection型は、組み合わせることでさらに柔軟な型定義が可能です。例えば、特定のオブジェクトにオプションで追加の情報を付加する場合などに、両者を活用することで、より直感 的で型安全なデータ構造を作成できます。
interface BasicInfo {
id: number;
name: string;
}
interface AdvancedInfo {
age: number;
email: string;
}
type UserInfo = BasicInfo & (AdvancedInfo | { address: string });
const user1: UserInfo = {
id: 1,
name: "Alice",
age: 30,
email: "alice@example.com"
};
const user2: UserInfo = {
id: 2,
name: "Bob",
address: "123 Main St"
};
この例では、UserInfo
型はBasicInfo
に加え、AdvancedInfo
またはaddress
プロパティを持つ型として定義されています。これにより、柔軟にユーザー情報を表現でき、どちらの情報形式も安全に扱うことができます。
まとめ
TypeScript
のUnion型とIntersection型を使い分けることで、データの柔軟な型定義が可能になり、コードの再利用性と安全性が向上します。Union型は「どちらか一つ」、Intersection型は「すべてを含む」場面で利用し、状況に応じて組み合わせて使うことで、より複雑なデータ構造を効率的に扱えるようになります。これらの型の使い方をマスターして、TypeScript
での型安全な開発をさらに強化しましょう。