- For functions with multiple type parameters, inference is all or nothing: either all type parameters are inferred or all must be specified explicitly.
- To get partial inference, use either classes or currying to create a new inference site.
- Prefer the currying approach if you'd like to create a local type alias.
//// // verifier:reset## Code Samples
export interface SeedAPI {
'/seeds': Seed[];
'/seed/apple': Seed;
'/seed/strawberry': Seed;
// ...
}
declare function fetchAPI<
API, Path extends keyof API
>(path: Path): Promise<API[Path]>;
fetchAPI<SeedAPI>('/seed/strawberry');
// ~~~~~~~ Expected 2 type arguments, but got 1.
const berry = fetchAPI<SeedAPI, '/seed/strawberry'>('/seed/strawberry'); // ok
// ^? const berry: Promise<Seed>
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'); // OK
// ^? const berry: Seed
fetcher.fetch('/seed/chicken');
// ~~~~~~~~~~~~~~~
// Argument of type '"/seed/chicken"' is not assignable to type 'keyof SeedAPI'
const seed: Seed = await fetcher.fetch('/seeds');
// ~~~~ Seed[] is not assignable to Seed
declare function getDate(mon: string, day: number): Date;
getDate('dec', 25);
declare function getDate(mon: string): (day: number) => Date;
getDate('dec')(25);
declare function fetchAPI<API>():
<Path extends keyof API>(path: Path) => Promise<API[Path]>;
const berry = await fetchAPI<SeedAPI>()('/seed/strawberry'); // OK
// ^? const berry: Seed
fetchAPI<SeedAPI>()('/seed/chicken');
// ~~~~~~~~~~~~~~~
// Argument of type '"/seed/chicken"' is not assignable to type 'keyof SeedAPI'
//
const seed: Seed = await fetchAPI<SeedAPI>()('/seeds');
// ~~~~ Seed[] is not assignable to Seed
const fetchSeedAPI = fetchAPI<SeedAPI>();
const berry = await fetchSeedAPI('/seed/strawberry');
// ^? const berry: Seed
declare function apiFetcher<API>(): {
fetch<Path extends keyof API>(path: Path): Promise<API[Path]>;
}
const fetcher = apiFetcher<SeedAPI>();
fetcher.fetch('/seed/strawberry'); // ok
function fetchAPI<API>() {
type Routes = keyof API & string; // local type alias
return <Path extends Routes>(
path: Path
): Promise<API[Path]> => fetch(path).then(r => r.json());
}