在類型層級進行解析
TypeScript 的範本文字類型與遞歸條件類型和 infer 相結合,可讓您完全在類型系統內解析和轉換字串文字。這不是運行時解析器,它是一個編譯時解析器,可以從字串常數中提取結構,從而為 URL 路由、SQL 查詢、命令列參數等啟用強型別 API。
模板文字類型 妝前乳
模板文字類型可以插入其他類型並推斷字串的一部分。
type Hello<T extends string> = `hello ${T}`;
type Result = Hello<"world">; // "hello world"
在條件類型中使用 infer ,您可以提取子字串:
type ExtractName<T extends string> =
T extends `hello ${infer Name}` ? Name : never;
type A = ExtractName<"hello alice">; // "alice"
type B = ExtractName<"goodbye bob">; // never
解析URL路由參數
一個常見的用例是從路由模式中提取路徑參數:
type RouteParams<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? { [K in Param | keyof RouteParams<Rest>]: string }
: T extends `${infer _Start}:${infer Param}`
? { [K in Param]: string }
: {};
這會在每個 : 前綴處遞歸地分割字串並建構一個物件類型。
type Params = RouteParams<"/users/:id/posts/:postId">;
// { id: string; postId: string }
更強大的路由解析器
上面的簡單版本因可選段或正規表示式約束而中斷。生產級解析器處理這些邊緣情況:
type ParseParam<T extends string> =
T extends `${infer _Prefix}:${infer Param}`
? Param extends `${infer Name}?`
? { [K in Name]?: string }
: { [K in Name]: string }
: {};
type Merge<T, U> = { [K in keyof T | keyof U]: K extends keyof T ? T[K] : K extends keyof U ? U[K] : never };
type ParseRoute<T extends string> =
T extends `${infer Segment}/${infer Rest}`
? Merge<ParseParam<Segment>, ParseRoute<Rest>>
: ParseParam<T>;
可選參數 (?) 成為結果類型中的可選屬性。
提取查詢字串
查詢字串解析遵循相同的模式:
type ParseQuery<T extends string> =
T extends `${infer First}&${infer Rest}`
? Merge<ParseSingle<First>, ParseQuery<Rest>>
: ParseSingle<T>;
type ParseSingle<T extends string> =
T extends `${infer Key}=${infer Value}`
? { [K in Key]: Value }
: {};
type Q = ParseQuery<"page=1&limit=10&sort=asc">;
// { page: "1"; limit: "10"; sort: "asc" }
對於實際使用,結合映射類型來轉換值:
type ParseInt<T extends string> =
T extends `${infer N extends number}` ? N : never;
type TypedQuery = {
[K in keyof Q]: K extends "page" | "limit" ? ParseInt<Q[K]> : Q[K];
};
// { page: 1; limit: 10; sort: "asc" }
實用的 API 類型模式
當您將解析器綁定到 API 函數時,真正的力量就會顯現出來:
function get<T extends string>(
path: T,
params: ParseRoute<T>
): void;
get("/users/:id/posts/:postId", {
id: "42",
postId: "99"
}); // OK
get("/users/:id", {
id: "42",
extra: "x"
});
// Error: 'extra' does not exist in { id: string }
typed-query-parser、ts-toolbelt 和 Hono 等庫使用這些技術來提供端到端類型安全,而無需運行時開銷。
限制
| 問題 | 影響 |
|---|---|
| 深度遞歸限制(~50 級) | 在很長的琴弦上斷裂 |
| 無正規表示式支援 | 無法驗證像 /^[a-z]+$/ 這樣的模式 |
| 沒有工會分裂 | 難以解析 `a |
| 編譯時成本 | 複雜的解析器會減慢 tsc |
概括
類型級解析器在編譯時將字串文字轉換為結構化類型。它們支援完全類型化的 URL 路由、查詢字串提取和配置解析,而無需產生程式碼。使用帶有 infer 的遞歸條件類型和模板文字來逐個字元地分離字串。密切注意遞歸深度和編譯時效能,但對於典型的路由用例,該模式是生產就緒的。

