TL;DR
- TypeScript では、型パラメータをすべて推論させるか、すべて明示するかのどちらかしか選べない。
- 一部だけを明示したいときは、クラスやカリー化で型パラメータを段階的に割り当てる。
内容
型パラメータは一部だけ明示できない
TypeScript では、型パラメータをすべて推論させるか、すべて明示的に指定するかを選ぶ必要がある。そのため、次のコードは型エラーになる。
function fetchAPI<API, Path extends keyof API>(path: Path): Promise<API[Path]> { ... }
export interface SeedAPI {
'/seed': Seed[]
'/seed/apple': Seed
'/seed/strawberry': Seed
}
fetchAPI<SeedAPI>('/seed/strawberry') // 型エラー: Expected 2 type arguments, but got 1.Path の型も渡せば解消するが、記述が冗長になる。
fetchAPI<SeedAPI, "/seed/strawberry">("/seed/strawberry")型パラメータを段階的に割り当てる
これを避けるには、型パラメータを段階的に渡す。1 つ目の方法はクラスを使うことである。
declare class ApiFetcher<API> {
fetch<Path extends keyof API>(path: Path): Promise<API[Path]>
}const fetcher = new ApiFetcher<SeedAPI>() // 明示的に指定
const berry = await fetcher.fetch("/seed/strawberry") // 型推論2 つ目の方法はカリー化である。
declare function fetchAPI<API>(): <Path extends keyof API>(path: Path) => Promise<API[Path]>const berry = await fetchAPI<SeedAPI>()("/seed/strawberry")どちらを採用してもよいが、カリー化ではローカルな型エイリアスを作れる。
function fetchAPI<API>() {
// ローカルな型エイリアス
type Routes = keyof API & string
return <Path extends Routes>(path: Path): Promise<API[Path]> => fetch(path).then((r) => r.json())
}