Skip to content

Latest commit

 

History

History
156 lines (110 loc) · 8.36 KB

inference-sites.md

File metadata and controls

156 lines (110 loc) · 8.36 KB

Item 28: Use Classes and Currying to Create New Inference Sites

Things to Remember

  • 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;
  // ...
}

💻 playground


declare function fetchAPI<
  API, Path extends keyof API
>(path: Path): Promise<API[Path]>;

💻 playground


fetchAPI<SeedAPI>('/seed/strawberry');
//       ~~~~~~~ Expected 2 type arguments, but got 1.

💻 playground


const berry = fetchAPI<SeedAPI, '/seed/strawberry'>('/seed/strawberry');  // ok
//    ^? const berry: Promise<Seed>

💻 playground


declare class ApiFetcher<API> {
  fetch<Path extends keyof API>(path: Path): Promise<API[Path]>;
}

💻 playground


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

💻 playground


declare function getDate(mon: string, day: number): Date;
getDate('dec', 25);

💻 playground


declare function getDate(mon: string): (day: number) => Date;
getDate('dec')(25);

💻 playground


declare function fetchAPI<API>():
  <Path extends keyof API>(path: Path) => Promise<API[Path]>;

💻 playground


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

💻 playground


const fetchSeedAPI = fetchAPI<SeedAPI>();
const berry = await fetchSeedAPI('/seed/strawberry');
//    ^? const berry: Seed

💻 playground


declare function apiFetcher<API>(): {
  fetch<Path extends keyof API>(path: Path): Promise<API[Path]>;
}

const fetcher = apiFetcher<SeedAPI>();
fetcher.fetch('/seed/strawberry');  // ok

💻 playground


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());
}

💻 playground