TL;DR
- レストパラメータとタプル型を使うと、シグネチャが引数の型に依存する関数をモデリングできる。
- 条件型を使うと、あるパラメータの型と他のパラメータの型の関係を表現できる。タプルの要素にはラベルを付ける。
内容
レストパラメータとタプル型
レストパラメータとタプル型を使うと、シグネチャが引数の型に依存する関数をモデリングできる。さらに条件型を使うと、あるパラメータの型と、それ以外のパラメータの型の関係をモデリングできる。次の buildURL は、ルートによってクエリパラメータが要るかどうかが変わる。
function buildURL<Path extends keyof RouteQueryParams>(
route: Path,
...args: RouteQueryParams[Path] extends null ? [] : [params: RouteQueryParams[Path]]
) {
const params = args[0]
return route + (params ? `?${new URLSearchParams(params)}` : "")
}呼び出し側で分かりやすいパラメータ名を表示するため、タプルの要素にはラベルを付ける。付けないと、次のように args_0 のような名前で表示される。
function buildURL<"/search">(
route: "/search",
args_0: {
query: string
language?: string
},
): string訳者による解説
特定の文字列と型が結びつくのは、JavaScript でよく見るパターンである。たとえば DOM のイベントハンドラでは、イベント名とイベントオブジェクトの型が結びついている(click と MouseEvent)。
この関係を次のように interface で定義する方法は、直感的で分かりやすいので広く使える。
interface RouteQueryParams {
"/": null
"/search": { query: string; language?: string }
}// OK
buildURL("/")
buildURL("/search", { query: "foo" })
buildURL("/search", { query: "bar", language: "en" })
// 型エラー
buildURL("/", { query: "recursion" })
buildURL("/search", {})