TypeScriptはJavaScriptに型の仕組みを追加した言語です。型を明確に指定できることで、開発時のエラーを早期に検出できたり、コードの可読性が向上するなどのメリットがあります。その中でも「ユニオン型」は、TypeScriptの強力な機能の一つです。
この記事では、ユニオン型の基本から応用までをわかりやすく解説します。TypeScriptを使った開発に慣れていない方でも理解できる内容となっていますので、ぜひ参考にしてください。
ユニオン型とは?
ユニオン型(Union Types)とは、複数の型を一つの変数に持たせることができる型のことです。つまり、ある変数がいくつかの異なる型の値を持つ可能性がある場合に使われます。
例えば、次のコードを見てください。
let value: string | number;
value = "Hello";
value = 123;
この例では、valueはstringまたはnumber型の値を持つことができます。これがユニオン型の基本的な考え方です。型の間には|(パイプ)を使い、複数の型を並べて記述します。
ユニオン型を使うことで、特定の変数やパラメータが複数の型を持つケースに対応することができ、柔軟なコードを書くことができます。
なぜユニオン型が必要なのか?
ユニオン型が便利な理由の一つは、型の柔軟性を確保しつつ、型安全性を維持できる点です。JavaScriptは動的型付けの言語なので、同じ変数に異なる型の値を代入することができます。しかし、TypeScriptでは型が厳密に管理されているため、異なる型を同じ変数に代入するとエラーになります。ユニオン型を使うことで、その制約を緩和しつつ、適切な型チェックを行うことができます。
例えば、ある関数の引数がstringまたはnumberのどちらかを受け取る場合、ユニオン型を使えば、引数の型チェックを柔軟に行うことができます。
function printValue(value: string | number) {
console.log(value);
}
printValue("TypeScript"); // "TypeScript"
printValue(2023); // 2023
上記のコードでは、printValue関数はstringかnumberのどちらかを引数に取ることができます。ユニオン型を使うことで、関数をより汎用的に作ることができ、コードの再利用性が向上します。
ユニオン型の使用時の注意点
ユニオン型を使う際に重要なのが、TypeScriptの型推論や型ガードを活用することです。ユニオン型を使うと、変数が複数の型を持つため、TypeScriptはどの型が実際に使われているかを自動的に判断する必要があります。しかし、場合によっては、開発者が明示的に型を判別する必要が出てきます。
例えば、次のようなケースを考えてみましょう。
function combineValues(value1: string | number, value2: string | number) {
return value1 + value2;
}
このコードは、エラーが発生します。なぜなら、TypeScriptはvalue1とvalue2がstring型かnumber型かを特定できないため、両方の型に共通の操作(この場合、+演算子)を許可していないからです。
この問題を解決するために、**型ガード(Type Guards)**という仕組みを使って、型の判別を行います。型ガードとは、特定の型であるかどうかを確認するための条件式のことです。
function combineValues(value1: string | number, value2: string | number): string | number {
if (typeof value1 === "string" && typeof value2 === "string") {
return value1 + value2; // 文字列結合
} else if (typeof value1 === "number" && typeof value2 === "number") {
return value1 + value2; // 数値の加算
} else {
return value1.toString() + value2.toString(); // 文字列として結合
}
}
このように、typeof演算子を使って値の型を判別し、それに応じて処理を分岐させることで、ユニオン型を適切に扱うことができます。
ユニオン型とインターセクション型の違い
ユニオン型と似た概念に**インターセクション型(Intersection Types)**があります。ユニオン型は「AかBかのどちらか」という意味合いを持つのに対して、インターセクション型は「AもBも両方」という意味合いを持ちます。
以下にインターセクション型の例を示します。
interface A {
a: string;
}
interface B {
b: number;
}
let obj: A & B = { a: "hello", b: 42 };
この場合、objはAとBの両方のプロパティを持つ必要があります。ユニオン型とインターセクション型は、異なる状況で使い分けることが重要です。
ユニオン型を使った型のリファクタリング
TypeScriptでは、ユニオン型を使った型の再定義やリファクタリングが効果的です。特に、コードベースが大きくなると、同じような型定義を何度も書くのは効率が悪いので、ユニオン型を活用して簡潔に表現できます。
type StringOrNumber = string | number;
function logValue(value: StringOrNumber) {
console.log(value);
}
このように、ユニオン型をtypeエイリアスとして定義しておくと、再利用性が向上し、コードがより読みやすくなります。
まとめ
ユニオン型は、TypeScriptの柔軟な型システムを支える重要な要素の一つです。複数の型を一つの変数に持たせることで、柔軟でかつ型安全なコードを書くことができます。ユニオン型を適切に使いこなすことで、TypeScriptの力を最大限に活用することができるでしょう。
ユニオン型のポイントまとめ
- ユニオン型は複数の型を組み合わせて使うことができる。
- 型ガードを活用して、正しい型に基づいた処理を行うことが重要。
- 型の再利用性やリファクタリングを考慮すると、
typeエイリアスが便利。
ユニオン型を使いこなすことで、より柔軟で堅牢なTypeScriptのコードを作成しましょう。

