TypeScript | 基礎文法:Union・基本型操作 – unionとintersectionの違い

TypeScript
スポンサーリンク

まずイメージでつかむ:unionとintersectionは「または」と「かつ」

最初に一番大事なことだけ頭に入れてください。

  • A | B(union型)
    「A または B」。どちらか一方ならOK。
  • A & B(intersection型)
    「A かつ B」。両方とも満たしていないとNG。

つまり、

「どっちかならいいよ」という“選択肢の型”が union
「両方の条件を同時に満たしてね」という“全部乗せの型”が intersection

このイメージをずっと軸にして、例を見ていきます。


具体例その1:オブジェクトで比べると違いが分かりやすい

union型(A または B)

まずは次の2つの型を用意します。

type HasName = {
  name: string;
};

type HasAge = {
  age: number;
};
TypeScript

これで union 型を作ります。

type NameOrAge = HasName | HasAge;
TypeScript

NameOrAge は「名前を持つ人」か「年齢を持つ人」のどちらかです。

const a: NameOrAge = { name: "Taro" }; // OK
const b: NameOrAge = { age: 20 };      // OK
const c: NameOrAge = { name: "Taro", age: 20 }; // これもOK(どっちも満たしている)
TypeScript

union は「どちらか一方を満たしていればOK」なので、
name だけでも age だけでも、両方あっても、全部OKです。

intersection型(A かつ B)

同じ2つの型を、今度は intersection 型で結びます。

type NameAndAge = HasName & HasAge;
TypeScript

これは「名前も年齢も持っている人」です。

const x: NameAndAge = { name: "Taro", age: 20 }; // OK

const y: NameAndAge = { name: "Taro" }; // エラー(age がない)
const z: NameAndAge = { age: 20 };      // エラー(name がない)
TypeScript

intersection は「両方満たしていないとダメ」なので、
name だけ・age だけでは不十分です。

ここでの違いを言い換えると、

  • union:HasNameHasAge のどれかを含む「ゆるい箱」
  • intersection:HasNameHasAge を両方含む「厳しい箱」

というイメージです。


具体例その2:関数の引数として考えると違いが光る

union型の引数:「どっちを渡してもいいよ」

type HasId = { id: number };
type HasEmail = { email: string };

type IdOrEmail = HasId | HasEmail;

function findUser(info: IdOrEmail) {
  // info が id を持っているか、email を持っているか、ここでは分からない
}
TypeScript

findUser は、「id だけ」でも「email だけ」でも呼べます。

findUser({ id: 1 });                 // OK
findUser({ email: "a@example.com" }); // OK
TypeScript

呼び出し側から見ると、「どっちを持っていてもいい」柔らかい関数です。
その代わり、関数の中では「どっちを持っているか分からない」ので、
if 分岐(型ガード)で絞り込んでから使う必要があります。

intersection型の引数:「両方そろってないと呼べない」

同じ2つを intersection で作ります。

type IdAndEmail = HasId & HasEmail;

function saveUser(info: IdAndEmail) {
  // info.id も info.email も安全に使える
}
TypeScript

saveUser を呼ぶには、id も email も両方必要です。

saveUser({ id: 1, email: "a@example.com" }); // OK

saveUser({ id: 1 });                         // エラー
saveUser({ email: "a@example.com" });        // エラー
TypeScript

ここでは、呼び出し側に対して

「この関数を使いたいなら、id も email もちゃんと用意してね」

という“厳しめの契約”を intersection 型で表現しています。

まとめると、

union 引数 → 「片方あれば呼べる。中ではどっちか分からないから、if で確認が必要」
intersection 引数 → 「両方なければ呼べない。中では何も気にせず両方使える」

という対比になります。


「できること」の違い:unionは制限され、intersectionは増える

union型の値は「共通部分だけ」直接使える

string | number を例にします。

function useUnion(value: string | number) {
  // value.toUpperCase(); // エラー
  value.toString();        // OK(両方にある)
}
TypeScript

理由はこうです。

value が string のときは toUpperCase がある
value が number のときは toUpperCase がない

「どっちか分からない」状態なので、
両方にあるメソッド(toString など)しか許されません。

つまり union 型は「守備範囲が広いぶん、何をしていいかは制限される」 型です。

intersection型の値は「両方のプロパティを持つ」

オブジェクトの intersection は逆に、「できること」が増えます。

type A = { a: string };
type B = { b: number };

type AB = A & B;

function useIntersection(value: AB) {
  console.log(value.a); // OK
  console.log(value.b); // OK
}
TypeScript

AB は A でもあり B でもあるので、A のプロパティも B のプロパティも両方使えます。

直感的には、

union:型の「候補」は増えるが、1つの値として「安全にできること」は減る
intersection:1つの値に「情報」を盛るので、できることは増える

という関係です。


設計の視点:いつ union を使い、いつ intersection を使うか

unionを選ぶべき場面

「どれか1つのパターンであればよい」というときです。例えば、

ID が文字列のときと数字のとき、両方ありうる
API レスポンスが「成功」か「エラー」のどちらか
状態が “idle” | “loading” | “success” | “error” のどれか

など、「いくつかのパターンのうち1つが現実に起こる」ものを表すのに向いています。

このとき、if / switch で「今どのパターンなのか?」を判定してから
それぞれに応じた処理を書くのが王道パターンです。

intersectionを選ぶべき場面

「この役割のものは、複数の性質を同時に持っている」ときです。例えば、

基本的なユーザー情報(id, name)
+ ログイン中である(token を持つ)
+ 管理者権限を持つ(isAdmin を持つ)

など、「複数の性質を全部持っていて初めて意味を持つ存在」を表すのに向いています。

関数でいうと、

この関数を呼ぶには A の情報も B の情報も必要
このオブジェクトは X としても Y としてもふるまえる

といった場面で intersection を使うと、設計意図がきれいに型に表れます。


最後に:自分の言葉で union と intersection を言い直してみる

ここまでを、あなた自身の言葉でこう言い換えてみてください。

union(|)は
「この値は A のときもあるし、B のときもある。どれか1つでいい。」

intersection(&)は
「この値は A でもあり、同時に B でもある。全部揃っていてほしい。」

そして、コードを書くたびに自分に問うのが大事です。

ここでは「どれか1つでいい」のか?
それとも「全部そろっていてほしい」のか?

その答えが |& の選択になります。

この「or か and か」を意識しながら型を書くようになると、
TypeScript の型は単なる“おまけ”ではなく、
あなたの頭の中のルールを、そのままコードに刻み込むための言語になっていきます。

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