【実務・中級編】 number型の定義と数値リテラル – TypeScript実践ガイド

TypeScriptの `number` 型と数値リテラルの深淵:実務で「ハマらない」ための境界線

やあ。コードレビューをしていて「あ、ここ危ないな」と直感的に感じるポイントがあるんだ。特に `number` 型。みんな軽く扱いがちだけど、TypeScriptにおける `number` は、JavaScriptの仕様である「IEEE 754 浮動小数点数」という巨大な氷山の一部に過ぎない。

今日は、中級エンジニアの君が「なんとなく」で書いている数値の扱いを、現場で「絶対にバグらせない」レベルまで引き上げるための話をしよう。

—

1. `number` 型の正体:JavaScriptの「すべて」を抱きしめる広さ

TypeScriptにおいて `number` を定義するということは、JavaScriptの `Number` オブジェクトが扱うあらゆる数値を許可することを意味する。

これには、整数や浮動小数点数だけでなく、`NaN` (Not a Number) や `Infinity` も含まれる。実務で一番怖いのは「APIから値が返ってくるはずが、計算過程で `NaN` になり、それがそのままUIに表示されてしまう」というケースだ。

// 現場でよくある「うっかり」
const calculateDiscount = (price: number, rate: number): number => {
return price rate;
};

// 0除算や不正な計算が混じると、TypeScriptはエラーを吐かないのに結果は NaN になる
const result = calculateDiscount(1000, 0 / 0);
console.log(result); // NaN が出力される

シニアからのアドバイス:
`number` をそのまま信用してはいけない。計算の境界値や、APIレスポンスのバリデーションには必ず `Number.isFinite()` を通す癖をつけよう。`NaN` や `Infinity` をフロントエンドのロジックに紛れ込ませないことが、堅牢なUIへの第一歩だ。

—

2. 数値リテラル型:型安全の「最強の制約」

中級者がステップアップするためにぜひ使ってほしいのが「数値リテラル型」だ。これは、単なる `number` ではなく、「この値しか許さない」という強力な制約を設ける手法だ。

例えば、UIコンポーネントのプロパティや、特定のステータスコードを扱う際に非常に効果的だ。

// 許容される値をリテラル型で定義する
type StatusCode = 200 | 400 | 401 | 500;

const handleResponse = (code: StatusCode) => {
// ここでは 200, 400, 401, 500 以外はコンパイルエラーになる
console.log(`現在のステータス: ${code}`);
};

handleResponse(200); // OK
// handleResponse(201); // コンパイルエラー: Argument of type ‘201’ is not assignable to parameter of type ‘StatusCode’.

これを活用すれば、`if` 文や `switch` 文での網羅性チェック(Exhaustiveness Checking)も強力に機能するようになる。

—

3. `number` と `BigInt` の決定的な違い

最近のフロントエンドでは、WebAssemblyとの連携や、高精度な暗号処理、あるいは巨大なIDの取り扱いで `BigInt` を見る機会が増えてきたはずだ。

ここで絶対に覚えておいてほしいのは、`number` と `BigInt` は型として完全に別物だということ。暗黙的な型変換は発生しない。

const num: number = 10;
const big: bigint = 10n;

// num + big; // コンパイルエラー! (Cannot mix ‘bigint’ and other types)

// 明示的な変換が必要
const result = BigInt(num) + big; // OK

なぜ別物なのか? それは精度が違うからだ。`number` は `2^53 – 1` を超えると精度を失うが、`BigInt` はメモリが許す限り無限に数値を扱える。実務で「IDが巨大すぎて末尾が0になる」というバグに遭遇したら、迷わず `BigInt`(あるいは文字列での管理)を検討してくれ。

—

4. 実務で役立つ「数値バリデーション」のベストプラクティス

最後に、現場でコピペして使える、数値の安全な取り扱いパターンを共有しておくよ。

/

  • 安全に数値へ変換するユーティリティ
  • APIからのレスポンスなど、信頼できない値に対して使う

/
const safeParseNumber = (value: unknown): number | null => {
const parsed = Number(value);

// NaNを除外し、かつ有限数であることを保証する
if (Number.isFinite(parsed)) {
return parsed;
}

return null; // 不正な値ならnullを返すことで、呼び出し元にハンドリングを強制する
};

// 使い方
const apiResponse = “123.45”;
const validatedPrice = safeParseNumber(apiResponse);

if (validatedPrice !== null) {
// ここでは確実に number 型として扱える
console.log(validatedPrice.toFixed(2));
}

まとめ:TypeScriptは「守ってくれる」のではなく「気づかせてくれる」

TypeScriptの `number` 型を攻略するコツは、「JavaScriptの緩い仕様を、TypeScriptの型システムでどれだけ厳格に囲い込めるか」にかかっている。

  • `number` は `Infinity` や `NaN` を含む「広すぎる」型であると意識する。
  • 特定の値が必要なら、リテラル型で徹底的に絞り込む。
  • 巨大な数値や精度の厳密さが求められるなら、迷わず `BigInt` へ。

型定義は、単なるドキュメントじゃない。君が書くロジックを守るための「防波堤」なんだ。明日からのコードレビューで、誰かの `number` の使い方が少しでも危うかったら、この話を思い出してアドバイスしてあげてほしい。

君の書くコードが、もっと堅牢で、もっと美しいものになることを期待しているよ。

コメント

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