こんにちは、白々さじきです。
昨日に引き続き最近TypeScriptを勉強することが多いので型の勉強を行っています。
私の学習のために生成AIに作らせた文章を共有します。
今回は、Union型です。
TypeScriptを勉強し始めると、エラーメッセージでよく見かける「Type ‘A’ is not assignable to type ‘B’」みたいな表示。そんな時に登場するのが「A | B」という書き方です。
今回は、この縦棒(|)を使った「union型」について、初心者の方でも理解できるように解説したいと思います。
この記事で解決すること
TypeScriptのunion型(A | B)が何を表しているのか分からない。型エラーが出たときに雰囲気で直していて、本当の意味が理解できていない。そんな悩みを解決します。
結論
union型は「AまたはBのどちらかの型」を表します。変数が複数の型のうちいずれかを取る可能性がある時に使う仕組みです。TypeScriptがより安全なコードを書くために用意してくれた機能だと理解しましょう。
union型って何?(超ざっくり説明)
union型は、日本語で言うと「AまたはB」という意味です。
例えば「string | number」と書いたら、「文字列または数値のどちらか」という意味になります。
let value: string | number;
value = "こんにちは"; // OK
value = 123; // OK
value = true; // エラー! boolean型は許可されていない
この縦棒(|)が「または」を意味していると覚えてください。英語では「union(結合)」と呼びます。
なぜunion型が必要なのか
実際のプログラムでは、「時と場合によって違う型が入る」という状況がよくあります。
よくあるシーン
例えば、ユーザーIDを扱う関数を考えてみましょう。
- 新規ユーザー → IDがまだないので「null」
- 既存ユーザー → IDは数値
この場合、「数値またはnull」という型が必要になります。
let userId: number | null;
userId = 12345; // ログイン済みユーザー
userId = null; // 未ログインユーザー
もしunion型がなかったら、どちらか一方しか扱えません。TypeScriptはこういう「どっちもありえる」状況を安全に扱うためにunion型を用意してくれています。
基本的な使い方
変数の型指定
let status: "pending" | "success" | "error";
status = "pending"; // OK
status = "success"; // OK
status = "completed"; // エラー!定義されていない
文字列リテラルを組み合わせて、「この3つの中からどれか」という制限もできます。これを「リテラル型のunion」と呼びます。
関数の引数や戻り値
function formatId(id: string | number): string {
return `ID: ${id}`;
}
formatId(123); // OK
formatId("ABC"); // OK
formatId(true); // エラー!
引数で「文字列または数値を受け取る」と指定できます。
よくある勘違いと初心者がつまずくポイント
勘違い1: 両方の型のメソッドが使えると思ってしまう
これは初心者が一番ハマるポイントです。
function process(value: string | number) {
console.log(value.toUpperCase()); // エラー!
}
「string | number」という型の変数に対して、stringのメソッド「toUpperCase()」を呼ぼうとするとエラーになります。
なぜなら、TypeScriptは「この変数、もしかしたらnumberかもしれないよね?」と考えるからです。numberには「toUpperCase」メソッドがないので、安全のためエラーを出します。
勘違い2: union型 = 両方の型を持つ
union型は「AまたはB」であって「AかつB」ではありません。
同時に両方の型を持つわけではなく、「どちらか一方」を表します。この違いは重要です。
初心者が混乱しやすいポイント: 型の絞り込みが必要
union型を使う場合、処理する前に「今この変数は実際どっちの型なのか」をチェックする必要があります。これを「型の絞り込み(Type Narrowing)」と言います。
function process(value: string | number) {
if (typeof value === "string") {
// ここではvalueはstring型として扱える
console.log(value.toUpperCase());
} else {
// ここではvalueはnumber型として扱える
console.log(value.toFixed(2));
}
}
このように、if文で型をチェックすることで、その内部では安全にそれぞれの型のメソッドを使えるようになります。
実例:悪い例から良い例へ
悪い例:型チェックなしで処理する
function displayPrice(price: string | number) {
// エラー!numberにはreplaceメソッドがない
return price.replace("円", "");
}
この関数は、priceが文字列だと決めつけて「replace」を呼んでいます。でも型定義では「string | number」なので、numberが渡される可能性もあります。これではエラーになります。
良い例:型を絞り込んでから処理する
function displayPrice(price: string | number): string {
if (typeof price === "string") {
// 文字列の場合の処理
return price.replace("円", "");
} else {
// 数値の場合の処理
return price.toString();
}
}
このように、最初に「今どっちの型か」をチェックしてから、それぞれに合った処理をします。これが正しい使い方です。
もう一つの例:APIレスポンスの処理
悪い例
type ApiResponse = {
data: string | null;
};
function showData(response: ApiResponse) {
// エラー!dataがnullの可能性がある
console.log(response.data.length);
}
良い例
type ApiResponse = {
data: string | null;
};
function showData(response: ApiResponse) {
if (response.data !== null) {
// ここではdataはstring型として扱える
console.log(response.data.length);
} else {
console.log("データがありません");
}
}
nullチェックをすることで、その後の処理で安全にstring型として扱えるようになります。
型の絞り込み(Type Narrowing)の基本
union型を使う上で避けて通れないのが「型の絞り込み」です。代表的な方法を3つ紹介します。
方法1: typeof による絞り込み
function format(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
プリミティブ型(string、number、booleanなど)の判定に使います。
方法2: === や !== による絞り込み
function getUserName(user: { name: string } | null) {
if (user !== null) {
return user.name;
}
return "ゲスト";
}
nullやundefinedをチェックする時によく使います。
方法3: in演算子による絞り込み
type Dog = { bark: () => void };
type Cat = { meow: () => void };
function makeSound(animal: Dog | Cat) {
if ("bark" in animal) {
animal.bark();
} else {
animal.meow();
}
}
オブジェクトの型を判定する時に便利です。「このプロパティがあるかどうか」で判断します。
今は「こういう方法があるんだ」と知っておけばOKです。実際に書いてみて慣れていきましょう。
まとめ:初心者が今押さえておくべきこと
TypeScriptのunion型について学びました。初心者の方は、以下のポイントを押さえておけば十分です。
- union型は「AまたはB」という意味で、縦棒(|)で書く
- 変数が複数の型のどれかを取りうる時に使う
- union型の変数に対しては、勝手にメソッドを呼べない
- 処理する前に「型の絞り込み」が必要
- typeof、===、inなどで型をチェックしてから使う
最初は「なんでこんなことしないといけないの?」と面倒に感じるかもしれません。でも、これはTypeScriptが「安全なコード」を書くために手伝ってくれている証拠です。
型エラーが出たら「TypeScriptが何を心配しているのか」を考える癖をつけると、だんだん理解が深まります。
焦らず、少しずつ慣れていきましょう。
サポートのお願い
下記リンクからお買い物いただけると、ブログ運営のための費用が増え、有料サービスを利用した記事作成が可能になります。ご協力よろしくお願いします!

コメント