こんにちは!TypeScriptの型システムの世界へようこそ。
日々フロントエンドからバックエンドまでコードを書いていると、「この文字列は、特定のルールに則ったものだけを受け付けたいのに、普通の `string` 型だと何でも通ってしまって不安だな…」と感じたことはありませんか?
他の言語からやってきた開発者なら、「正規表現でバリデーションをかければいいや」と思うかもしれません。もちろんそれは実行時(Runtime)の正解です。しかし、私たちTypeScript使いには、「コードを書いた瞬間、コンパイルの時点で不穏な文字列を完全に弾き飛ばす」という強力な武器があります。
今回は、TypeScriptの真骨頂である Template Literal Types(テンプレートリテラル型) を使って、関数の引数名を型レベルで動的にバリデーションする極意を一緒にマスターしていきましょう!
ここをクリアすれば、あなたの型定義の引き出しは一気にプロの領域に到達しますよ。
—
1. 文字列を「型」として操る:Template Literal Types とは?
TypeScriptでは、単なる `string` という大雑把な型だけでなく、「特定の文字列そのもの」を型として扱うことができます(これを Literal Types と呼びます)。
さらに、ES6のテンプレート構文のように、そのリテラル型を組み合わせて新しい型を作り出せるのが Template Literal Types です。
頭の中で次のようなイメージを持ってみてください。
[普通の string 型] : アメーバのように何でも飲み込む(穴だらけ)
[Literal 型] : 型が「”user_id”」のようにガチガチに固定されている
[Template Literal] : 「”user_” + 任意の文字列」のように、型をパズルや数式のように組み立てる
これを利用すると、「特定のプレフィックス(接頭辞)から始まる文字列しか受け付けない」というルールを、コンパイラに厳格に強制させることができるんです。
—
2. 実装:プレフィックス付きの引数を型安全に受け取る関数
では、具体的にコードを見ていきましょう。
今回は、データベースの操作をイメージして、`data-` から始まる属性名のみを受け付ける関数を作ってみます。
以下のコードをじっくり読んでみてください。
// 1. 「”data-” で始まる文字列」という型を定義する
// `${…}` の中でテンプレートリテラル型を駆使します
type DataAttributeKey = `data-${string}`;
// 2. その型を引数に取る関数を定義する
function setElementAttribute(key: DataAttributeKey, value: string): void {
console.log(`Setting ${key} to ${value}`);
}
// — 【使用例】 —
// ✅ コンパイル成功:正しく “data-” から始まっています
setElementAttribute(“data-user-id”, “12345”);
setElementAttribute(“data-theme”, “dark”);
// ❌ コンパイルエラー:プレフィックスがないため、TypeScriptが赤線を引いて怒ります!
// Error: Argument of type ‘”user-id”‘ is not assignable to parameter of type ‘`data-${string}`’.
setElementAttribute(“user-id”, “12345”);
// ❌ コンパイルエラー:違うプレフィックスも当然弾かれます
// Error: Argument of type ‘”aria-label”‘ is not assignable to parameter of type ‘`data-${string}`’.
setElementAttribute(“aria-label”, “main”);
コードのここがポイント!
`type DataAttributeKey = \`data-\${string}\`;` という定義がこのマジックの核心です。
これは、「`data-` という文字の後に、どんな文字列(`string`)が来てもいいけれど、先頭は絶対に `data-` で始まっていてね」という型レベルの制約書を意味しています。
もし、開発者がうっかり `”user-id”` や `”aria-label”` を渡そうものなら、TypeScriptのコンパイラがビルド(またはエディタ上)の瞬間に、「おいおい、ルール違反の文字列が入っていますよ」と教えてくれるわけです。実行時エラーを未然に防ぐ、最高に知的なアプローチだと思いませんか?
—
3. さらに応用:ジェネリクスと組み合わせた高度な動的バリデーション
「特定のプレフィックス」だけでなく、「特定のプレフィックスの後に、指定したドメイン名(例えば `id` か `name`)しか許さない」という、さらに厳密なバリデーションをやってみたくなってきた頃合かと思います。
ここでは、TypeScriptのジェネリクス(型引数)と Template Literal Types を組み合わせて、より実践的な動的バリデーションを実装してみましょう。
// 許可するサフィックス(接尾辞)を限定する
type AllowedSuffix = “id” | “name” | “email”;
// プレフィックスとサフィックスを動的に結合した型を作る
type DynamicFieldKey
// 関数にジェネリクスを適用する
function fetchUserData
console.log(`Fetching field: ${field}`);
}
// — 【使用例】 —
// ✅ コンパイル成功:”user_” の後ろが “id” なのでOK
fetchUserData(“user_id”);
// ✅ コンパイル成功:”user_” の後ろが “name” なのでOK
fetchUserData(“user_name”);
// ❌ コンパイルエラー:”age” は AllowedSuffix に含まれていないため弾かれる
// Error: Argument of type ‘”user_age”‘ is not assignable to parameter of type ‘”user_id” | “user_name” | “user_email”‘
fetchUserData(“user_age”);
脳内トレース:型はどう評価されているか?
1. `AllowedSuffix` に `”id” | “name” | “email”` というユニオン型(選択肢)を定義します。
2. `DynamicFieldKey
3. 結果として、TypeScript内部では `AI` のように自動で以下の型が生成されたのと同義になります:
`”user_id” | “user_name” | “user_email”`
4. そのため、関数を呼び出す際にも IDE(VSCodeなど)のオートコンプリート(入力補完)が効くようになり、「`user_` と打つと候補が出てくる」という極上の開発体験が手に入ります。
—
4. 初学者が陥りやすい文法エラーと注意点
Template Literal Types を使い始めの頃によくやってしまう、代表的な「罠」をいくつか紹介しておきますね。ここを知っておくだけで、無駄なハマり時間をゼロにできます。
罠その1:テンプレートリテラルの中で `string` 以外の型を雑に混ぜる
// ❌ 意図しない型になってしまう例
type BadKey = `item_${number}`;
// これ自体はエラーになりませんが、TypeScriptの `number` は「すべての数値」を指すため、
// 実際には “item_1”, “item_42” だけでなく、NaN や無限大なども型の上では許容されてしまいます。
対策: 厳密にコントロールしたい場合は、前述のようにユニオン型(`”1″ | “2” | “3”` など)を組み合わせるか、数値であってもリテラル型で絞り込む意識を持ちましょう。
罠その2:バックティーク(` `)ではなく、シングルクォーテーション(`’`)で囲ってしまう
// ❌ Syntax Error になります
type InvalidType = ‘data-${string}’;
// ⭕ 正しくはバックティーク(JISキーボードなら Shift + @ など)です
type ValidType = `data-${string}`;
テンプレートリテラル型は、JavaScriptのテンプレート文字列と同様にバックティークを使用します。ここを間違えると一発でコンパイルエラーになるので注意してくださいね。
—
おわりに:型は「制約」ではなく「開発者の最高の相棒」
今回は、Template Literal Types を用いた関数引数の動的バリデーションについて解説しました。
- 文字列を単なるデータではなく、「型」として構造化して捉えること
- プレフィックスやサフィックスを組み合わせて、コンパイル時にルールを強制すること
- エディタの補完と連動させることで、バグを仕込む余地を物理的に消し去ること
これらは、モダンなTypeScriptアーキテクチャにおいて必須の教養であり、あなたの書くコードの信頼性を劇的に引き上げてくれます。
「ここをクリアすれば、TypeScriptの基本はバッチリマスターできますよ!」
ぜひ明日の開発から、この動的バリデーションのテクニックを取り入れて、型パズルのような美しいコードを楽しんでみてください。それでは、次のステップでお会いしましょう!