【入門編】 テンプレートリテラル型における型推論 – TypeScript実践ガイド

こんにちは!TypeScriptの世界へようこそ。チーフアーキテクトの私です。

日々のフロントエンド開発、本当にお疲れ様です。「`string`型や`number`型はなんとなくわかったけれど、なんだか最近、先輩たちが呪文みたいな記号を使ってすごい型を作っていてチンプンカンプン……」そんな風に悩んでいませんか?

大丈夫ですよ、安心してください。最初は誰もが「なんだこれ!」と頭を抱えます。今日は、そのモヤモヤをスッキリ解消するために、テンプレートリテラル型と`infer`(インファー)という、ちょっと魔法みたいな文字列の分解・抽出テクニックについて、おしゃべりするような気持ちで紐解いていきましょう。

—

1. 文字列型を「お菓子のパッケージ」に例えてみよう

突然ですが、スーパーやコンビニでお菓子を買うときのことを想像してみてください。「いちご味のポテトチップス」とか、「塩キャラメル味のポップコーン」みたいに、商品の名前には「味(フレーバー)」と「おやつの名前」がセットで書かれていますよね。

例えば、プログラムの世界でこんな文字列があったとします。

`”flavor:chocolate”` (チョコレート味)
`”flavor:strawberry”` (ストロベリー味)

私たち人間が見れば「あ、これは味の指定なんだな、中身は chocolate だな」と一瞬で分かりますが、TypeScriptの型システムにも同じことを教えてあげたいのです。

「`flavor:`というお決まりのパッケージ(目印)剥がして、中のフレーバーの名前だけを取り出したい!」

そんなワガママを叶えてくれるのが、テンプレートリテラル型と`infer`キーワードのコンビネーション技です。

—

2. `infer` ってなに?(新米アルバイトくんに例えてみる)

`infer` は、英語の「infer(推論する)」から来ています。TypeScriptの型の中で使われるとき、こいつは「優秀だけどちょっと控えめな新米アルバイトくん」だと思ってください。

あなたが「この段ボール箱の中身、開けなくても何か当ててみてよ」と箱を渡すと、アルバイトくん(`infer`)は中をチラッと覗き込んで、

「あ、これ、たぶん『chocolate』ですね!」

と、型をシュッと見つけて(推論して)取り出してくれるのです。この「見つけて変数(プレースホルダー)に一時的に格納する」という役割を、`infer` が一手に引き受けてくれます。

—

3. 実践!文字列をパカッと分解してみよう

百聞は一見にしかず。実際にコードを書いてみましょう。
お手元のエディタを開いている方は、ぜひコピペして動きを確認してみてくださいね。

// ① まず、文字列のパターンを分解する型を作ります
// 「flavor:〇〇」という形にマッチさせ、〇〇の部分を「flavorName」という変数にキャプチャします
type ExtractFlavor = T extends `flavor:${infer flavorName}`
? flavorName // マッチしたら、アルバイトくんが見つけた flavorName を返す!
: never; // マッチしなかったら「そんなのないよ(never)」と返す

// ② 実験してみましょう!
// “flavor:chocolate” という文字列の型から、中身を取り出してみます
type MyFavorite = ExtractFlavor<"flavor:chocolate">;
// 結果:type MyFavorite = “chocolate” (おおっ、綺麗に取り出せた!)

type AnotherFavorite = ExtractFlavor<"flavor:strawberry">;
// 結果:type AnotherFavorite = “strawberry”

// もし全然違う文字列を渡したらどうなる?
type WeirdSnack = ExtractFlavor<"tasty:cookie">;
// 結果:type WeirdSnack = never (パターンに合わないので、ちゃんとハネられます)

すごいでしょう? `extends` の左側と右側でパターンをパズルピースのように合わせにいって、「あ、ここに入るのはこれだな」と `infer` が見事にくり抜いてくれるのです。

—

4. Web制作の現場でどう役立つの?(リアルなユースケース)

「へえ、面白い仕組みなのはわかったけど、実際のWeb制作やアプリ開発のどこで使うの?」という疑問が湧くはずです。

例えば、CSSのクラス名や、APIから返ってくるルーティングのパス(URLの構造)、コンポーネントのイベント名などを厳密に型で縛りたいときによく使います。

「`user:profile`」「`user:settings`」のような、「`[機能]:[アクション]`」という命名規則(プレフィックス付きの文字列)があるとします。ここから「アクションの部分だけ」を取り出して、ボタンがクリックされたときの関数の引数の型として縛りたい、なんてときにこのテクニックが爆発的な威力を発揮します。

// アプリのイベント名を表す型たち
type AppEvent = “click:button” | “hover:link” | “submit:form”;

// 「冒頭のアクション名(click や hover など)」だけを抜き出す型職人
type ExtractAction = T extends `${infer action}:${string}` ? action : never;

// 抽出された型を確認してみる
type ActionsOnly = ExtractAction;
// 結果:type ActionsOnly = “click” | “hover” | “submit”
// すべてのイベント名から、コロンの前側だけがきれいに抽出されました!

これ、手作業で型を書き直していたら、イベントが増えるたびに地獄を見ますよね。でも、この型定義を一度作っておけば、新しいイベントが追加されても、TypeScriptが勝手にルールを解釈して型を更新してくれます。保守性がグッと上がって、現場のエンジニアみんなが笑顔になります。

—

最後に:一歩ずつ、楽しみながら進もう

テンプレートリテラル型と `infer` の組み合わせは、最初はまるで暗号のように見えるかもしれません。「なんだか難しそう……」と尻込みしてしまう気持ち、本当によく分かります。私も最初はチンプンカンプンでした。

でも、焦る必要は全くありません。
まずは「文字列のパズルを解いてくれる便利な仕組みなんだな」「`infer` は中身を当ててくれるアルバイトくんなんだな」というイメージだけ心に留めておいてください。

日々のコーディングの中で、「あ、ここ、文字列をパキッと分割できたら気持ちいいのにな」という瞬間に出会ったら、ぜひ今日のお話を思い出して、そっとコードを書いてみてくださいね。

あなたのTypeScriptライフが、より楽しく、快適なものになりますように。
それではまた、次の現場でお会いしましょう!チーフアーキテクトでした。

コメント

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