TypeScript | 基礎文法:変数・基本型 – 数値リテラル型

TypeScript
スポンサーリンク

数値リテラル型とは何か

数値リテラル型は、「特定の数値だけを許可する型」です。
普通の number 型は「どんな数値でもOK」ですが、数値リテラル型は「この変数には 1 しか入れてはいけない」「01 のどちらかだけ」といった、取り得る値をきわめて限定した型を表現します。

let n1: number;
n1 = 1;
n1 = 100;  // どんな数値でもOK

let n2: 1;
n2 = 1;    // OK
// n2 = 2; // エラー:Type '2' is not assignable to type '1'
TypeScript

n2 の型は number ではなく、「値が 1 のときだけ許される型」です。
これが数値リテラル型の一番シンプルなイメージです。


数値リテラル型とユニオン型の組み合わせ

「取り得る数値が決まっている」場面を型で表現する

数値リテラル型が本領発揮するのは、ユニオン型と組み合わせたときです。
たとえば、「サイコロの目は 1〜6 のどれか」という制約を、そのまま型にしてみます。

type Dice = 1 | 2 | 3 | 4 | 5 | 6;

let d: Dice = 3;  // OK
// d = 7;         // エラー:Type '7' is not assignable to type 'Dice'
TypeScript

Dice は「1, 2, 3, 4, 5, 6 のいずれか」という型です。
7 や 0 を代入しようとすると、コンパイル時に止められます。

同じように、「フラグとして 0 か 1 だけを使いたい」といった場面も表現できます。

type Bit = 0 | 1;

let b: Bit = 0;
b = 1;
// b = 2; // エラー
TypeScript

現実世界の「取り得る値が限られている数」を、そのまま型に落とし込めるのが数値リテラル型の強みです。


const と数値リテラル型の関係

const で宣言すると「その値の型」になる

const で数値を宣言すると、その変数は多くの場合「数値リテラル型」として扱われます。

const ONE = 1;
// ONE の型は 1

let two = 2;
// two の型は number
TypeScript

const ONE は再代入できないので、「この変数は一生 1 のまま」とコンパイラは判断できます。
その結果、型としても「1」というリテラル型にまで絞り込めます。

一方 let two は将来 3 や 4 になるかもしれないので、「number 全体」として扱われます。

定数と型をリンクさせる

この性質を使うと、「定数」と「型」をきれいに結びつけられます。

const LEVEL_EASY = 1 as const;
const LEVEL_NORMAL = 2 as const;
const LEVEL_HARD = 3 as const;

type Level = typeof LEVEL_EASY | typeof LEVEL_NORMAL | typeof LEVEL_HARD;

let lv: Level = LEVEL_NORMAL;
// lv = 4; // エラー
TypeScript

typeof LEVEL_EASY は「1 型」、typeof LEVEL_NORMAL は「2 型」です。
それらをユニオンした Level は、「1, 2, 3 のどれか」という型になります。
定数の値と型定義がズレにくくなるので、実務でもよく使うパターンです。


数値リテラル型が守ってくれるもの

「本当はあり得ない値」をコンパイル時に排除する

数値リテラル型を使うと、「number では広すぎて防げないバグ」をかなり潰せます。

たとえば、難易度を 1〜3 の数値で表すとします。

type Difficulty = 1 | 2 | 3;

function setDifficulty(d: Difficulty) {
  // ...
}

setDifficulty(1);
setDifficulty(3);
// setDifficulty(4); // エラー
TypeScript

Difficulty がただの number だったら、4 や 100 も通ってしまいます。
数値リテラル型にしておけば、「その値は許可されていない」とコンパイル時に教えてくれます。

switch 文との相性

数値リテラル型は switch 文とも相性がいいです。

type Dice = 1 | 2 | 3 | 4 | 5 | 6;

function describe(d: Dice): string {
  switch (d) {
    case 1:
      return "one";
    case 2:
      return "two";
    case 3:
      return "three";
    case 4:
      return "four";
    case 5:
      return "five";
    case 6:
      return "six";
  }
}
TypeScript

Dice が 1〜6 に限定されているので、「7 のケースを書き忘れた」といった心配はそもそもありません。
将来、もし値のパターンを増やしたくなったら、type Dice の定義を変えるだけで、足りない分岐があればコンパイラが教えてくれます。


初心者がまず掴んでおきたい数値リテラル型の感覚

数値リテラル型は、こう捉えると分かりやすいです。

「number は“どんな数でもOK”」
「数値リテラル型は“この数だけOK”」
「複数の数値リテラル型を | でつなぐと、“この中のどれかだけOK”という型になる」

そして、実際のコードの中で、

サイコロの目(1〜6)
難易度レベル(1〜3)
フラグ(0 / 1)

のように、「取り得る数値が限られている場面」が出てきたら、
「これ、ただの number じゃなくて数値リテラル型にできないかな?」と一度考えてみる。

その一歩を踏むだけで、「本当はあり得ない値」が紛れ込む余地を、型レベルでかなり削ることができます。

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