TypeScriptのunion型とは?「AかBか」の型の書き方を初心者向けに解説

TypeScriptのunion型とは?「AかBか」の型の書き方を初心者向けに解説

 

TypeScriptのunion型とは

TypeScriptのunion型(リテラル型)の仕組みの図解

TypeScriptのunion型(ユニオン型)とは、「AかBのどちらか」というように、複数の型のいずれかを表す型です。縦棒|で型をつなげて書きます。

少年A
“success” | “error” みたいな縦棒でつなぐやつ、あれ何なの?
キノ
それがunion型。実務だと状態管理とかで毎日のように使うから、押さえておくと強いよ
スポンサーリンク

なぜunion型が必要なのか

1つの値が「複数の型のどれか」になる場面は、実務でよくあります。例えば、入力欄に入れるIDが「数値のときも文字列のときもある」といったケースです。

// numberでもstringでも受け取りたい
function printId(id: number | string) {
  console.log(`IDは${id}です`);
}

printId(123);      // OK
printId("abc123"); // OK

number | stringと書くことで、「numberかstringのどちらか」を受け取れる関数になります。union型がないと、型ごとに関数を分けて書く必要が出てしまいます。

スポンサーリンク

リテラル型とは

union型と一緒によく使われるのが「リテラル型」です。リテラル型とは、stringnumberのような広い型ではなく、「特定の値そのもの」を型にしたものです。

let status: "success"; // "success"という文字列しか入れられない型
status = "success"; // OK
status = "error";   // Error: Type '"error"' is not assignable to type '"success"'.

単体だとあまり使い道がなさそうですが、union型と組み合わせると一気に実用的になります。

union型×リテラル型が実務で最強な理由

リテラル型をunion型でつなぐと、「決められた選択肢のどれか」を表現できます。

type Status = "loading" | "success" | "error";

function showMessage(status: Status) {
  // statusには この3つ以外は渡せない
}

showMessage("success"); // OK
showMessage("finish");  // Error: 決められた値以外は渡せない

API通信の状態(読み込み中・成功・失敗)や、ボタンの種類(primary・secondaryなど)のように、「あらかじめ決まった値のどれか」を扱う場面で大活躍します。文字列を直接比較するより、タイプミスをコンパイル時に防げるのが大きなメリットです。この書き方はtypeでしか書けないので、interfaceとの使い分けも押さえておくとよいです。

union型の値を安全に使う(型の絞り込み)

union型の値をそのまま使おうとすると、エラーになることがあります。

function printId(id: number | string) {
  console.log(id.toUpperCase());
  // Error: Property 'toUpperCase' does not exist on type 'number'.
}

toUpperCaseは文字列のメソッドなので、numberの可能性があるidには使えません。こういうときは、typeofで型を確認してから使います(型の絞り込み)。

function printId(id: number | string) {
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // ここではstringとして扱える
  } else {
    console.log(id); // ここではnumber
  }
}

この「使う前に型を確認する」考え方は、any・unknownの記事でも解説しています。union型でも同じ型ガードの考え方が使えます。

Reactでの使用例

ReactでAPI通信の状態を管理するとき、union型のリテラル型が定番の書き方になります。

type Status = "loading" | "success" | "error";

const [status, setStatus] = useState("loading");

// statusには決められた3つの値しか入らないので、
// タイプミスや想定外の値を防げる

API通信の型については、こちらの記事も参考になります。

union型とenumの違い

「決められた値のどれか」を表す方法として、enumという書き方もあります。ざっくり言うと、union型のリテラル型の方がシンプルで、近年のReact開発ではこちらが好まれる傾向があります。

項目union型(リテラル型)enum
書き方シンプル(1行で書ける)やや冗長
コンパイル後余分なコードが残らない実体のあるコードが生成される

enum自体については、別の記事で改めて詳しく解説する予定です。まずはunion型のリテラル型を使いこなせるようにしておけば十分です。

よくあるエラー

type Status = "success" | "error";
const s: Status = "Success";
// Type '"Success"' is not assignable to type 'Status'.

これは、大文字・小文字の違いで、決められたリテラル型に一致していないために起きるエラーです。union型のリテラル型は「値そのもの」を型にしているため、"success""Success"は別物として扱われます。定義した値と完全に一致しているか確認してみてください。

よくある質問

Q. union型はいくつまで型をつなげられますか?
A. 個数に実用上の制限はありません。"a" | "b" | "c" | "d"のように必要なだけつなげられます。

Q. リテラル型とunion型は違うものですか?
A. 別の概念です。リテラル型は「特定の値そのものの型」、union型は「複数の型のどれか」を表す型で、この2つを組み合わせて使うことが多いです。

Q. union型とenum、どちらを使えばいいですか?
A. 近年のReact開発では、シンプルに書けるunion型のリテラル型が好まれる傾向があります。まずはこちらに慣れておけば困りません。

まとめ

  • union型は|で複数の型をつなぎ、「AかBのどちらか」を表す型
  • リテラル型(特定の値の型)と組み合わせると、「決まった選択肢のどれか」を表現できる
  • union型の値を使うときは、typeofなどで型を絞り込んでから使う
  • ReactのAPI状態管理などで頻繁に使う、実務必須の書き方

公式ドキュメントにも、union型についての詳しい解説があります。

TypeScript公式ドキュメント:Union Types

少年A
“loading” | “success” | “error”、これは確かによく見るわ
キノ
うん。この形を自分で書けるようになると、一気に「TypeScriptっぽいコード」が書けるようになるよ

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です