union型配列とは何か(まずイメージから)
union型配列は、「この配列には“いくつかの型のどれか”が入る」ということを型で表現したものです。
たとえば「number か string のどちらかが入る配列」は、こう書きます。
const values: (number | string)[] = [1, "2", 3, "4"];
TypeScript(number | string)[] は「number または string の配列」という意味です。
要素ごとに number だったり string だったりしてもよくて、とにかく「この2種類以外は入れない」という約束を型で表現しています。
union型配列の基本形と読み方
(A | B)[] という形に慣れる
union型配列の基本形は、(A | B)[] です。
かっこの中が「要素として許される型の選択肢」、その後ろの [] が「その配列」という意味になります。
type Id = number | string;
const ids: Id[] = [1, 2, "3", "4"];
TypeScriptこの場合、ids は「number か string のどちらかである Id 型の配列」です。Id[] は (number | string)[] と同じ意味になります。
ここで大事なのは、「配列の中に“混ざっていてもいい”」ということです。
1番目が number、2番目が string、3番目が number…のように、順番もバラバラで構いません。
union型配列でできること・できないこと
許される値と弾かれる値
type Value = number | string;
const values: Value[] = [1, "2", 3];
values.push(4); // OK(number)
values.push("5"); // OK(string)
// values.push(true); // エラー(boolean は Value ではない)
TypeScriptValue が number | string なので、そのどちらかなら配列に追加できます。
逆に、boolean のように union に含まれていない型は、コンパイル時に弾かれます。
「何でもアリ」ではなく、「この中のどれかだけアリ」というのが union型配列の重要なポイントです。
取り出したときの型に注意する
const v = values[0];
// v の型: number | string
TypeScript取り出した要素の型は number | string になります。
つまり、「どちらか分からない」状態なので、そのままでは数値メソッドも文字列メソッドも安全に呼べません。
// v.toFixed(2); // エラー(string かもしれない)
// v.toUpperCase(); // エラー(number かもしれない)
TypeScriptここで必要になるのが「型ガード」です。
if (typeof v === "number") {
console.log(v.toFixed(2)); // ここでは number として扱える
} else {
console.log(v.toUpperCase()); // ここでは string として扱える
}
TypeScriptunion型配列は、「入れるときは柔軟」「使うときはちゃんと確認してから」というスタイルになります。
(A | B)[] と A[] | B[] の違いは超重要
「要素が混ざる」のか「配列の種類が2パターンある」のか
よく混同されるのが、次の2つです。
let a: (number | string)[];
let b: number[] | string[];
TypeScript(number | string)[] は、「1つの配列の中に number と string が混ざっていてもいい」型です。
一方 number[] | string[] は、「この変数には number の配列か string の配列のどちらかが入る」という意味で、
1つの配列の中で混ざることは想定していません。
a = [1, "2", 3]; // OK
// b = [1, "2", 3]; // NG(number[] でも string[] でもない)
b = [1, 2, 3]; // OK(number[])
b = ["a", "b"]; // OK(string[])
TypeScript「要素レベルで混ざる」のが union型配列((A | B)[])、
「配列そのものが2パターンある」のが配列の union(A[] | B[])です。
ここを意識して書けるようになると、型設計の精度が一気に上がります。
union型配列を使うべき場面・避けるべき場面
使うべき場面のイメージ
「この配列には、仕様として複数種類の値が混ざる」と決まっているときに、union型配列は力を発揮します。
ログの配列(数値IDと文字列メッセージが混ざる)
type LogItem = number | string;
const logs: LogItem[] = [1, "start", 2, "end"];
TypeScript検索結果の配列(ユーザーか記事か、どちらかが入る)
type UserResult = { type: "user"; name: string };
type ArticleResult = { type: "article"; title: string };
type SearchResult = UserResult | ArticleResult;
const results: SearchResult[] = [
{ type: "user", name: "Taro" },
{ type: "article", title: "TypeScript入門" }
];
TypeScriptこのように、「混ざること自体が仕様」であり、その仕様を型で表現したいときに union型配列はとても有効です。
避けた方がいい場面のイメージ
一方で、「とりあえず何でも突っ込んでいるだけ」の配列を union型配列でごまかすのは危険です。
const data = [1, "Taro", true];
// 型: (number | string | boolean)[]
TypeScriptこの配列を見て、「これは何の配列?」と聞かれて、うまく説明できないなら、
本当はオブジェクトや別の構造にした方がいい可能性が高いです。
const user = {
id: 1,
name: "Taro",
isActive: true
};
TypeScript「異なる型を混ぜたい」と思ったときは、
「それは本当に1つの配列に混ぜるべきか?」
「オブジェクトやタプルの方が自然じゃないか?」
と一度立ち止まるクセをつけると、設計がぐっと良くなります。
初心者がまず身につけたい union型配列の感覚
union型配列の本質は、「この配列には“この中のどれか”だけが入る」という制約を型で表現することです。
(number | string)[] と書いた瞬間に、
「number か string 以外は入れない」
「取り出したときは number | string だから、ちゃんと絞り込んでから使う」
という2つのルールが自動的に生まれます。
大事なのは、「混ぜること」そのものではなく、
「何が混ざるのか」「なぜ混ざるのか」を型で説明できているかどうか。
そこまで言語化できた union型配列は、
ただの“ごちゃ混ぜ配列”ではなく、あなたの仕様をそのまま映した、強いデータ構造になります。
