typescript - Hur man korrekt typiserar generiska funktioner i postvärden?


I nästa exempel har params-argumentet till getParamsKey korrekt typ, hämtad från query-fältet, men resultatet i mergeResults har typen any.

Förväntat resultat: både argumenten och resultatet är korrekt typade.

type User = {id: number}

const getUser = async ({id}: {id: number}): Promise<User> => ({
  id,
})

const getUsers = async ({page = 1, pageSize = 5}): Promise<User[]> => []

type QueryInfo<P, R> = {
  query: (params: P) => Promise<R>
  mergeResults: (oldResult: R, newResult: R, params: P) => R
}

const makeQueries = <T extends object>(queries: {[K in keyof T]: QueryInfo<T[K], any>}) => queries

const queries = makeQueries({
  getUsers: {
    query: getUsers,

    // PROBLEM results has type `any`, params are properly typed
    mergeResults: (oldResult, newResult, params) => newResult, 
  },
  getUser: {
    query: getUser,

    // PROBLEM results has type `any`, params are properly typed
    mergeResults: (oldResult, newResult, params) => newResult,
  },
})

// PROBLEM queries results have `any` type
queries.getUser.query
queries.getUsers.query

Lekplats

Svar #1

En av lösningarna

type User = {id: number}

const getUser = async ({id}: {id: number}): Promise<User> => ({
  id,
})

const getUsers = async ({page = 1, pageSize = 5}): Promise<User[]> => []

type QueryInfo<P, R> = {
  query: (params: P) => Promise<R>
  mergeResults: (oldResult: R, newResult: R, params: P) => R
}

const makeQueries = <T, Q>(queries: {[K in keyof (T&Q)]: K extends (keyof (T | Q)) ? QueryInfo<T[K], Q[K]> : never}) => queries

const queries = makeQueries({
  getUsers: {
    query: getUsers,
    mergeResults: (oldResult, newResult, params) => newResult,
  },
  getUser: {
    query: getUser,
    mergeResults: (oldResult, newResult, params) => newResult,
  },
})


queries.getUser.query
queries.getUsers.query

Lekplats

Svar #2

Förutom att använda en separat hjälpfunktion makeQuery som hjälper till att härleda det inre objektet tror jag inte att det är möjligt (eller det är möjligt men du kommer att stöta på vissa begränsningar som att ReturnType inte kommer att härledas)

Hjälpfunktionen makeQuery kommer att hjälpa dig att koppla query och mergeResults så att returtypen också kommer att användas:

const makeQuery = <P, R>(query: QueryInfo<P, R>) => query;

TypeScript Playground - https://tsplay.dev/NDVD4W

Relaterade artiklar