I'm using tRPC in a project with already existing API calls and would like to wrap the useQuery function into a separate wrapper, but I'm struggling with getting the TypeScript types right.
What I want
Here is what the ideal outcome looks like. Instead of the following code:
const query = trpc.myendpoint.useQuery({ foo: 'bar' });
... I would like to write this:
const query = useCustomHook(trpc.myendpoint, { foo: 'bar' });
Non-Typescript Solution
The JavaScript part is easy to implement but I struggle in getting the TypeScript types right. I want the useCustomHook to return the correct data type. Here is my any hack which technically works but provides no type hints:
function useCustomHook(obj: any, queryData: any) {
// ... Here I have some code related to my old code, which is why I need the custom hook
return obj.useQuery(queryData);
}
What I tried so far
I tried the code below already and also tried inferring types but did not get it to work. These were some of my approaches in which I already did not know how to type queryData properly:
// Approach using the trpc object
type TrpcProcedure1 = (typeof trpc)[keyof typeof trpc];
function useCustomHook<T extends TrpcProcedure>(obj: TrpcProcedure1, queryData: ???) {}
// Error when calling obj.useQuery:
// Property 'useQuery' does not exist on type 'TrpcProcedure'.
// Approach going via AppRouter['_def']['procedures']
type TrpcProcedure2 = (typeof trpc)[keyof AppRouter['_def']['procedures']];
function useCustomHook<T extends TrpcProcedure>(obj: TrpcProcedure2, queryData: ???) {}
// Error when calling obj.useQuery:
// This expression is not callable. Each member of the union type 'ProcedureUseQuery<...>' has signatures, but none of those signatures are compatible with each other
Unfortunately, both resulted in error messages as written.
I managed to get it to work (thanks to help from the tRPC discord):
Using this code, the input as well as the output is properly typed.
DecorateProcedure<QueryProcedure, U, V>is the procedure type, whereQueryProcedure extends AnyQueryProcedure. The input parameters can then be inferred viainferProcedureInput<QueryProcedure>. Similarly, the output type can be inferred viainferProcedureOutput<QueryProcedure>and then wrapped intoUseTRPCQueryResult.