TypeScriptを書いていて、Pathの処理を型でやらなきゃいけない場面がありその際に使用したので復習がてら書いていきます。
infer
= 推論すると覚えておくと理解が楽かもです。
簡単な使用例
inferはConditional Typesの中で使われる型演算子です。inferは「推論する」という意味でextendsの右辺にのみ書くことができます。
最初にこれを読んだ時、あんまりわからなかったので理解のとっかかりになるような簡単な使用例を書いてみます。
type Infer<T> = T extends Array<infer U> ? U : never;
type a = Infer<[1, 2, 3]>;
// → type a = 3 | 1 | 2
type b = Infer<1>;
// → type b = never
inferでやる内容ではないけど...
この例では、Infer
はなにかしらを受け取り、それが(infer U)[]
にマッチした場合、U
を返す。そうでない場合はnever
を返す。
aの例では、[1, 2, 3]
がArray<infer U>
にマッチするので、U
は1 | 2 | 3
となり、そのまま返される。
bの例では、1
はマッチしないので、
never`が返される。
この例を見た上で、最初に提示した以下の文章を読めば、なんとなく納得できるかと思います。
inferはConditional Typesの中で使われる型演算子です。inferは「推論する」という意味でextendsの右辺にのみ書くことができます。
少し複雑めな使用例
ここでは少し複雑な使用例を紹介したいと思います。
要件としては、以下のようなURLパスを型で表現する必要があります。
- openapiのパスパラメータは、
/users/{id}
のように{}
で囲まれた部分がパラメータである - MSWのリクエストハンドラは、
/users/:id
のようにパラメータ部分が:
で始まる形式である必要がある - パスパラメータは複数である場合がある(
/users/{id}/post/:postId
など)
つまり、/users/{id}
を/users/:id
に変換する型が必要です。
これを型で表現するために、以下のような型を作りました。
type PathParams<T extends string> =
T extends `${infer Head}/{${infer Param}}${infer Tail}`
? `${Head}/:${Param}${PathParams<Tail>}`
: T;
type c = PathParams<'/users/{id}'>;
// → type c = "/users/:id"
type d = PathParams<'/users/{id}/post/:postId'>;
// → type d = "/users/:id/post/:postId"
PathParams
は、T
が/users/{id}
である場合、/users/:id
のようなパスに変換する型です。
再起的に処理しているため、/users/{id}/post/{postId}
のような複数のパラメータがある場合も対応できます。
infer
を使うとこういう型もかなり簡潔に書くことができたりします。
おわりに
最後まで読んでいただきありがとうございます。
今回は、infer
を使った型の処理について紹介しました。
私自身もまだまだ型に関しては勉強中なので、間違いや誤解がある場合はコメントいただけると嬉しいです🙇♂️