コードを読んでいて `”success” | “error”` のような書き方を見かけたことはありませんか?

リテラル型ってなんですか?プリミティブ型と何が違うんだろう…
"success" | "error" みたいな書き方を見かけるけど、これって型なの?
ユニオン型と組み合わせるって聞いたけど、実際どう使えばいいのかイメージできない

この記事では、リテラル型の概念と書き方を、プリミティブ型との比較を使いながらやさしく説明します。「特定の値だけを受け付ける型」を定義する方法から、ユニオン型との組み合わせ、よく使われる実用例まで順番に見ていきましょう。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • TypeScriptのstring・number型は理解したが、リテラル型はまだよく知らない方
  • "success" | "error" のような書き方の意味を知りたい方
  • typeエイリアスとユニオン型の組み合わせをどう使えばいいか気になっている方
  • constとletで型推論が変わると聞いて、なぜなのか気になっている方

この記事を読むと、リテラル型を使って「使える値を限定した型」が自分で書けるようになります。ユニオン型と組み合わせてtypeエイリアスを作る書き方も身につきます。

それでは、順を追って詳しく見ていきましょう!

リテラル型とは — string型とどう違うのか

リテラル型とは — string型とどう違うのか

プリミティブ型(string / number など)は「どんな文字列でも」「どんな数値でも」受け付ける型です。リテラル型は、そこからもう一歩踏み込んで、「この値しか受け付けない」という制約をかける型です。

【TypeScript】プリミティブ型ってなに?5つの基本型をわかりやすく解説
【TypeScript】プリミティブ型ってなに?5つの基本型をわかりやすく解説TypeScript初心者向けにプリミティブ型をやさしく解説。string・number・boolean・null・undefinedの基本と書き方がすぐわかります。...

「どんな値でも入る型」と「特定の値しか入らない型」の違い

まず、プリミティブ型とリテラル型を並べて比べてみましょう。

// string型:どんな文字列でも入る
let status1: string = "success";
status1 = "error";      // OK
status1 = "pending";    // OK
status1 = "何でも入る"; // OK

// リテラル型:"success"という値しか入らない
let status2: "success" = "success";
status2 = "error"; // エラー! "success"以外は入れられない

string 型は「文字列であればなんでもOK」なのに対して、"success" というリテラル型は 「”success”という値そのものを型にしたもの」 です。型チェックの段階でTypeScriptが「この変数には”success”しか入れられない」と守ってくれます。

リテラル型の基本の書き方(文字列・数値)

リテラル型の書き方はとてもシンプルです。型を書く位置に、具体的な値をそのまま書くだけです。

// 文字列リテラル型
let direction: "left" = "left";

// 数値リテラル型
let one: 1 = 1;

最初は「そんな厳しい制約、いつ使うの?」と感じるかもしれません。でもユニオン型と組み合わせると「決まった選択肢の中からしか選べない型」が作れるようになって、一気に実用的になります。

ユニオン型と組み合わせると何ができるか

ユニオン型と組み合わせると何ができるか

リテラル型を単独で使うと「1つの値しか入れられない型」になって少し窮屈です。ここにユニオン型を組み合わせると、「この値かあの値のどちらか」 という実用的な型が作れます。

“success” | “error” のように複数の値を許容する書き方

ユニオン型は |(パイプ)を使って、複数の型を「どれでもOK」とつなぐ書き方です。リテラル型と組み合わせると次のようになります。

// "success"か"error"のどちらかしか入れられない
let status: "success" | "error";
status = "success"; // OK
status = "error";   // OK
status = "pending"; // エラー! "pending"は含まれていない

string 型にしていたら "pending" も入ってしまいますが、リテラル型のユニオンにすることで 「使える値を決まった選択肢に絞る」 ことができます。変な値が紛れ込むのを型チェックの段階で防げるのがポイントです。

typeエイリアスで名前を付けて使いやすくする

実務のコードでは、同じユニオン型を複数の場所で使うことがよくあります。そのたびに "success" | "error" と書くのは手間ですし、後で選択肢を変えたいとき全箇所を修正しなければなりません。

そこで使えるのが type エイリアスです。ユニオン型に名前を付けて、再利用できる型として定義します。

// typeエイリアスで名前を付ける
type Status = "success" | "error" | "loading";

// 変数の型として使える
let currentStatus: Status = "loading";

// 関数の引数・戻り値にも使える
function getLabel(status: Status): string {
  return `現在のステータス: ${status}`;
}

Status という名前を付けることで、「これはステータスを表す型だ」という意味が一目でわかるようになります。 コードが読みやすくなり、後からのメンテナンスもしやすくなります。

constで宣言するとリテラル型に推論される

constで宣言するとリテラル型に推論される

リテラル型の話をしていると、型推論との関係でつまずきやすいポイントがあります。それが、constとletで型推論の結果が変わるという話です。

letとconstで型推論の結果が変わる理由

型注釈(: string などの型指定)を省略したとき、TypeScriptは変数の型を自動で推論します。このとき、letconst では推論される型が変わります。

// letで宣言:string型に推論される
let direction = "left"; // 型は string

// constで宣言:リテラル型に推論される
const direction2 = "left"; // 型は "left"(リテラル型)

なぜかというと、let は後から値を変えられるので、TypeScriptは「どんな文字列でも入る可能性がある」と判断して string 型に広げます。 一方で const は値が変わらないことが確定しているので、「この変数は “left” という値しか持たない」と判断して、リテラル型として推論するのです。

型推論の仕組みそのものについては以下の記事で詳しく解説していますので、気になる方はあわせて読んでみてください。

【TypeScript】型推論ってなに?型を書かなくても型が決まる仕組みを解説
【TypeScript】型推論ってなに?型を書かなくても型が決まる仕組みを解説TypeScriptの型推論を初心者向けにやさしく解説。型を書かなくても型が決まる仕組みや、省略できる場面・書くべき場面がすっきりわかります。 ...

意図せずリテラル型になっているとき・そうでないとき

この仕組みを知っておくと、思わぬエラーを回避できます。

type Direction = "left" | "right";

function move(dir: Direction): void {
  console.log(`${dir}に移動します`);
}

// constで宣言した場合:リテラル型 "left" として推論される → そのまま渡せる
const d1 = "left";
move(d1); // OK

// letで宣言した場合:string型として推論される → エラーになる
let d2 = "left";
move(d2); // エラー! string型はDirection型に渡せない

d2 に入っている値は "left" ですが、TypeScriptが推論する型は string です。move() が求めているのは Direction"left" | "right")なので、より広い型である string はそのまま渡せません。

「値は合ってるのにエラー?」と感じるときは、このconst/letの推論の違いを疑ってみてください。let で宣言した変数を渡したい場合は、型注釈を明示して let d2: Direction = "left" と書けばエラーは解消されます。

リテラル型を関数の引数に使う(よくある使い方)

リテラル型を関数の引数に使う(よくある使い方)

リテラル型が最もよく登場するのは、関数の引数に「受け付ける値の選択肢を限定する」目的で使うケースです。実際のコードで見てみましょう。

type Direction = "up" | "down" | "left" | "right";

function move(direction: Direction): void {
  console.log(`${direction}に移動します`);
}

move("up");       // OK
move("down");     // OK
move("diagonal"); // エラー! Directionに含まれていない

引数の型を string にしてしまうと何でも渡せてしまい、意図しない値でコードが壊れる可能性があります。リテラル型のユニオンで型を定義しておくと、「想定外の値が渡ってきたらコンパイル時点でエラーにする」 というチェックが自動で効くようになります。

VSCodeなどのエディタを使っていれば、move() と書いた後に使える値の候補が自動補完で表示されるのも便利なところです。

enumとの使い分けはどう考えるか

enumとの使い分けはどう考えるか

「リテラル型のユニオンと似たようなことがenumでもできる」と聞いたことがある方もいるかもしれません。確かにenumでも選択肢を定義した型は作れます。

// enumを使った場合
enum Direction {
  Up = "up",
  Down = "down",
}

// リテラル型のユニオンを使った場合
type Direction = "up" | "down";

どちらも「決まった選択肢を持つ型」を作れる点は同じです。ただ、enumはTypeScript独自の仕様が強く出る機能で、コミュニティでも「非推奨」という意見が聞かれます。リテラル型のユニオンのほうがシンプルに書けるので、特別な理由がなければこちらで十分です。

【付録】さらに学びを深めるためのリソース


さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。

おすすめの書籍

ゼロからわかる TypeScript入門


技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。

変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。

プロを目指す人のためのTypeScript入門


技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。

オンラインで参照できる公式ドキュメント

TypeScript公式ハンドブック


https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。

TypeScript Deep Dive


https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。

TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。


まとめ — リテラル型はこう使う

まとめ — リテラル型はこう使う

この記事で学んだことを整理しておきましょう。

リテラル型とは、string 型や number 型のような「どんな値でも入る型」ではなく、「この値だけを受け付ける型」 のことです。"success"1 のように、具体的な値をそのまま型として書きます。

実用的に使うために押さえておきたいポイントは3つです。

  • ユニオン型と組み合わせる。 "success" | "error" のように | でつなぐと「どちらかの値だけを受け付ける型」になります。
  • typeエイリアスで名前を付ける。 type Status = "success" | "error" のように定義すると、意味が伝わりやすく再利用しやすくなります。
  • constで宣言するとリテラル型として推論される。 let では広い型(string など)に推論されます。この違いを知っておくとエラーで迷いにくくなります。

※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。