型レベルのミニルートパーサー
ルートパスを型付きのパラメーターオブジェクトに解析します。
「型レベルのミニルートパーサー」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。
目標
ルートパーサーを構築します。このパーサーは"users/:id/posts/:postId"のようなパスを読み取り、完全にコンパイル時に、型付きの params オブジェクト{ id: string; postId: string }を生成します。これは型付きルーターで実際に使われているパターンです。
type Params = ParseRoute<"users/:id/posts/:postId">;
// Goal: { id: string; postId: string }パラメーターを認識する
パスのセグメントは、":"で始まる場合にパラメーターです。テンプレートリテラルでこのプレフィックスに一致させ、コロンの後にあるパラメーター名を推論します。
表記: 実際の TypeScript では、テンプレートリテラル型を、ドル記号と波括弧の穴を含むバッククォートで囲まれた文字列として記述します。ここでのスニペットでは、そのパターンをTpl<...>として表し、各部分を順番に並べています。たとえば、リテラルのプレフィックスに続く Rest に一致するバッククォートテンプレートは、Tpl<'prefix', infer Rest>と表します。
type ParamName<S> = S extends Tpl<':', infer Name> ? Name : never;
// Tpl<...> denotes a backtick template literal type: a colon then Name
type X = ParamName<':id'>; // 'id'
type Y = ParamName<'users'>; // neverパスを分割する
まず、Split型を再利用して、ルートを"/"でセグメントに分割します。各セグメントは、リテラルまたはパラメーターのいずれかになります。
type Split<S extends string, Sep extends string> =
S extends Tpl<infer H, Sep, infer T> ? [H, ...Split<T, Sep>] : [S];
// Tpl<H, Sep, T> = a template literal type matching H, then Sep, then T
type Segs = Split<'users/:id', '/'>; // ['users', ':id']テンプレートの直接再帰
先に分割せず、セグメントを1つずつ一致させて元の文字列を直接解析することもできます。次の"/"までを一致させ、そのセグメントを処理してから、残りの部分に対して再帰します。
type ParseRoute<S extends string> =
S extends Tpl<infer Seg, '/', infer Rest>
? SegParam<Seg> & ParseRoute<Rest>
: SegParam<S>;
// Tpl<Seg, '/', Rest> matches a segment, a slash, then the restセグメントごとのパラメーター
ヘルパーは、1つのセグメントを、パラメーターであれば1プロパティのオブジェクトに、リテラルであれば空のオブジェクトに変換します。
type SegParam<S extends string> =
S extends Tpl<':', infer Name> ? { [K in Name]: string } : {};
// Tpl<':', Name> matches a colon followed by the param name
type X = SegParam<':id'>; // { id: string }
type Y = SegParam<'posts'>; // {}交差型で組み合わせる
各セグメントが持つ params を交差型で組み合わせます。交差型の中では空のオブジェクトが消えるため、最終的な型には実際のパラメーターだけが残ります。
type Params = ParseRoute<"users/:id/posts/:postId">;
// { id: string } & {} & { postId: string } & {}
// = { id: string; postId: string }解析をたどる
"users/:id/posts/:postId"の場合:
- Seg "users" -> {} 、":id/posts/:postId" に対して再帰
- Seg ":id" -> { id: string }、"posts/:postId" に対して再帰
- Seg "posts" -> {}、":postId" に対して再帰
- Seg ":postId" -> { postId: string }、基本ケース
type Final = { id: string } & { postId: string };結果を整える
オブジェクトの交差型は、そのままでは表示が扱いにくくなります。「prettify」ヘルパーは、キーに対する mapped type を使って交差型を1つの見やすいオブジェクト型に平坦化します。
type Prettify<T> = { [K in keyof T]: T[K] } & {};
type Clean = Prettify<ParseRoute<"users/:id">>; // { id: string }パーサーを使用する
解析した型を関数に組み込み、ハンドラーが正しく型付けされた params を受け取れるようにします。存在しないキーを渡すとコンパイルエラーになります。
declare function route<P extends string>(
path: P,
handler: (params: Prettify<ParseRoute<P>>) => void
): void;
route("users/:id", p => { const id: string = p.id; });型付き params の利点
コンパイラーは、ルート文字列そのものからparamsを導出できるようになりました。パス内のパラメーター名を変更すると、すべてのハンドラーで期待されるキーが自動的に更新されます。手動のインターフェースは不要で、ルートとハンドラーのずれも生じません。
route("users/:userId", p => {
const u = p.userId; // ok
// const x = p.id; // error: id does not exist
});パーサーを拡張する
このミニパーサーは、完全な型付きルーターの基礎になります。セグメントごとのヘルパーにさらにテンプレートパターンを追加すれば、型付きの値(数値パラメーター)、ワイルドカード、省略可能なセグメントにも対応できます。再帰的なテンプレート構造は変わりません。
type SegParam2<S extends string> =
S extends Tpl<':', infer N, '(number)'> ? { [K in N]: number }
: S extends Tpl<':', infer N> ? { [K in N]: string }
: {};
// Tpl<...> stands for a backtick template literal type pattern理解度チェック
ルートパーサーについての理解度を確認します。
まとめ
コンパイル時に動作するルートパーサーを構築しました。
- 再帰的なテンプレートリテラル推論で各セグメントに一致させます。
- パラメーターセグメント(
:name)は{ name: string }になります。 - リテラルセグメントは
{}になり、交差型の中で消えます。 Prettifyによって、結果が見やすい params に平坦化されます。
次はコース25で、tRPC を使ったエンドツーエンドの型安全性を扱います。
よくある質問
「型レベルのミニルートパーサー」レッスンは無料ですか?
はい。「型レベルのミニルートパーサー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。
「型レベルのミニルートパーサー」で何を学びますか?
ルートパスを型付きのパラメーターオブジェクトに解析します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
TypeScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「型レベルのミニルートパーサー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このTypeScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- パーサーコンビネーターの概念
- 型レベルの文字列分割
- テンプレートリテラルによる解析
- 型レベルのミニルートパーサー