TypeScriptでは文字列にstring型だけを使ってはいけない

TypeScriptを使っていると、文字列が入る変数をstring型で済ませてしまう場面が多くあります。

しかし、日付、ID、特定のフォーマットを持つコードなどを扱う際は、文字列にstring型を使うのはあまりに無防備です。

なぜstringだけでは不十分なのか?

例えば、日付を扱う変数を考えてみましょう。

TypeScript
const date: string = '2026-12-34'; // 文法的には正しいが、日付としては不正

string型は「どんな文字でも受け入れる」ため、上記のようなあり得ない日付も許容してしまいます。

これが関数の引数やAPIのレスポンス定義に使われていると、実行した際に初めてエラーが発覚し、デバッグに時間を取られることになります。

テンプレートリテラル型による「構造の定義」

TypeScriptには文字列のパターンを型として定義できる「Template Literal Types」という機能があります。

これを利用すると、特定のフォーマットに従わない文字列をコンパイル時点でエラーにできます。

例えば、日付フォーマット(YYYY-MM-DD)を定義した場合は以下のようになります。

TypeScript
// 1桁の数字(0埋めあり)
type OneToNine = '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09';

// 月(01〜12)
type Month = OneToNine | '10' | '11' | '12';

// 日(01〜31)
// ※厳密には各月の日数までは制御できませんが、基本的な桁と範囲を絞り込めます
type Day = OneToNine | `1${number}` | `2${number}` | `30` | `31`;

// 日付文字列の型(YYYY-MM-DD)
type DateString = `${number}${number}${number}${number}-${Month}-${Day}`;

// 正常なケース
const date: DateString = '2026-04-22'; 

const invalidMonth: DateString = '2026-13-21';
// Error: Type '"13"' is not assignable to type 'Month'

const invalidFormat: DateString = '2026/04/22';
// Error: 型が一致しない (- ではなく / になっている) 

テンプレートリテラル型によるメリット

型を定義したコードを読むだけで「この変数はYYYY-MM-DD形式でなければならない」という意図が明確に伝わります。

また、VS Codeなどのエディタであれば、エラーがあれば入力中にリアルタイムで画面上にエラーが表示されるので、すぐに間違えに気づくことができます。

VS Codeなどのエディタであれば、エラーがあれば入力中にリアルタイムで画面上にエラーが表示されるので、すぐに間違えに気づくことができます。

前述の例は日付でしたが、メールアドレスのような特定の型を持つものはテンプレートリテラル型にすることができるので、安全性の観点から、string型のままにしないほうが望ましいです。

TypeScript
// メールアドレスの型
// ※厳密な型ではないが、string型よりは間違えを検出しやすい
type Email = `${string}@${string}.${string}`;

// 正常なケース
const validEmail: Email = "user@example.com";

const invalidEmail: Email = "user@examplecom";
// Error: メールアドレス形式になっていない

まとめ

TypeScriptでは「とりあえずstring型」にしてしまいがちですが、それでは値の正しさまでは保証できません。

特に日付やID、特定フォーマットの文字列を扱う場合、string型のままだと不正な値をコンパイル時に検出できず、実行時エラーの原因になります。

テンプレートリテラル型を活用すれば、文字列に構造的な制約を持たせることができ、型の時点で不正な値を防ぐことが可能になります。

これにより、コードの安全性が向上するだけでなく、型から意図が明確に伝わるため、可読性や保守性の向上にもつながります。