TypeScriptのリテラル型とは?書き方とユニオン型との組み合わせをやさしく解説
コードを読んでいて `”success” | “error”` のような書き方を見かけたことはありませんか?
"success" | "error" みたいな書き方を見かけるけど、これって型なの?
この記事では、リテラル型の概念と書き方を、プリミティブ型との比較を使いながらやさしく説明します。「特定の値だけを受け付ける型」を定義する方法から、ユニオン型との組み合わせ、よく使われる実用例まで順番に見ていきましょう。
この記事は次のような方におすすめです。
- TypeScriptのstring・number型は理解したが、リテラル型はまだよく知らない方
"success" | "error"のような書き方の意味を知りたい方- typeエイリアスとユニオン型の組み合わせをどう使えばいいか気になっている方
- constとletで型推論が変わると聞いて、なぜなのか気になっている方
この記事を読むと、リテラル型を使って「使える値を限定した型」が自分で書けるようになります。ユニオン型と組み合わせてtypeエイリアスを作る書き方も身につきます。
それでは、順を追って詳しく見ていきましょう!
- 未経験で後悔したくない
【実体験】未経験からITエンジニアに転職して後悔した話|4社経験してわかった「最初の選択ミス」 - 年収が低くて不安
4年間ずっと年収260万だったエンジニアが、転職で510万になるまでの全記録
リテラル型とは — string型とどう違うのか
プリミティブ型(string / number など)は「どんな文字列でも」「どんな数値でも」受け付ける型です。リテラル型は、そこからもう一歩踏み込んで、「この値しか受け付けない」という制約をかける型です。
「どんな値でも入る型」と「特定の値しか入らない型」の違い
まず、プリミティブ型とリテラル型を並べて比べてみましょう。
// 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とletで型推論の結果が変わるという話です。
letとconstで型推論の結果が変わる理由
型注釈(: string などの型指定)を省略したとき、TypeScriptは変数の型を自動で推論します。このとき、let と const では推論される型が変わります。
// letで宣言:string型に推論される
let direction = "left"; // 型は string
// constで宣言:リテラル型に推論される
const direction2 = "left"; // 型は "left"(リテラル型)
なぜかというと、let は後から値を変えられるので、TypeScriptは「どんな文字列でも入る可能性がある」と判断して string 型に広げます。 一方で const は値が変わらないことが確定しているので、「この変数は “left” という値しか持たない」と判断して、リテラル型として推論するのです。
型推論の仕組みそのものについては以下の記事で詳しく解説していますので、気になる方はあわせて読んでみてください。
意図せずリテラル型になっているとき・そうでないとき
この仕組みを知っておくと、思わぬエラーを回避できます。
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 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を活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。



