'Generic Wrapper function where passed function is already typed
Background:
I am using graphql-code-generator to generate React Query hooks from my schema. These are effectively just wrappers for the standard React Query hooks (useQuery/useMutation) but automatically inject relevant variables into the query keys and query itself (such as an id).
However, these generated 'wrapper' hooks cannot be used directly for SSR prefetches because they do not immediately expose query keys (if any). This can be solved by exposing the getKey and fetcher functions allowing me to prefetch whilst maintaining consistency with the generated code. A hook now looks something along the line of this:
export const useCurrentUserQuery = <
TData = CurrentUserQuery,
TError = unknown
>(
client: GraphQLClient,
variables?: CurrentUserQueryVariables,
options?: UseQueryOptions<CurrentUserQuery, TError, TData>,
headers?: RequestInit['headers']
) =>
useQuery<CurrentUserQuery, TError, TData>(
variables === undefined ? ['CurrentUser'] : ['CurrentUser', variables],
fetcher<CurrentUserQuery, CurrentUserQueryVariables>(client, CurrentUserDocument, variables, headers),
options
);
useCurrentUserQuery.getKey = (variables?: CurrentUserQueryVariables) => variables === undefined ? ['CurrentUser'] : ['CurrentUser', variables];
;
useCurrentUserQuery.fetcher = (client: GraphQLClient, variables?: CurrentUserQueryVariables, headers?: RequestInit['headers']) => fetcher<CurrentUserQuery, CurrentUserQueryVariables>(client, CurrentUserDocument, variables, headers);
(The types here are also generated to match the GraphQL schema)
Then I can use the following in getServerSideProps to prefetch the data server side:
const queryClient = new QueryClient()
await queryClient.prefetchQuery(
useMyHookQuery.getKey(variables), // Gets key
await useMyHookQuery.fetcher(variables) // 'Manually' runs query
)
return queryClient // To run dehydrate etc
However, given I might be doing this quite a lot I would like to be able to write a generic function which takes the generated hook as an argument (since it's just an object in JS), performs this prefetch and then returns the QueryClient.
Question:
I essentially trying to type this plain JS function assuming fn is the useCurrentUserQuery hook above:
const prefetchQueryOnServer = async (fn, variables) => {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(
fn.getKey(variables),
fn.fetcher(client, variables)
)
return queryClient
}
Note: client is a GraphQLClient object from graphql-request.
There are several bits I am unsure of how to do:
- The
getKeyandfetchermethods have been attached to theuseCurrentUserQueryfunction after the fact. How do you type this properly? - I appreciate what I'm trying to do involves getting the argument types (
TReactQueryHook<A extends any[], R> = (...args: A) => Promise<R>) for each level, but nested generics get confusing very quickly! Some explanation would be appreciated.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
