Inferring Types
In addition to the type inference made available by @trpc/server
(see here) this integration also provides some inference helpers for usage purely in React.
Infer React Query options based on your router
When creating custom hooks around tRPC procedures, it's sometimes necessary to have the types of the options inferred from the router. You can do so via the inferReactQueryProcedureOptions
helper exported from @trpc/react-query
.
trpc.tsts
import {createTRPCReact ,typeinferReactQueryProcedureOptions ,} from '@trpc/react-query';import type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';// infer the types for your routerexport typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export typeRouterOutputs =inferRouterOutputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();
trpc.tsts
import {createTRPCReact ,typeinferReactQueryProcedureOptions ,} from '@trpc/react-query';import type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server';// infer the types for your routerexport typeReactQueryOptions =inferReactQueryProcedureOptions <AppRouter >;export typeRouterInputs =inferRouterInputs <AppRouter >;export typeRouterOutputs =inferRouterOutputs <AppRouter >;export consttrpc =createTRPCReact <AppRouter >();
usePostCreate.tsts
import {trpc ,typeReactQueryOptions ,typeRouterInputs ,typeRouterOutputs ,} from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useUtils ();returntrpc .post .create .useMutation ({...options ,onSuccess (post ) {// invalidate all queries on the post router// when a new post is createdutils .post .invalidate ();options ?.onSuccess ?.(post );},});}
usePostCreate.tsts
import {trpc ,typeReactQueryOptions ,typeRouterInputs ,typeRouterOutputs ,} from './trpc';typePostCreateOptions =ReactQueryOptions ['post']['create'];functionusePostCreate (options ?:PostCreateOptions ) {constutils =trpc .useUtils ();returntrpc .post .create .useMutation ({...options ,onSuccess (post ) {// invalidate all queries on the post router// when a new post is createdutils .post .invalidate ();options ?.onSuccess ?.(post );},});}
usePostById.tsts
import {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}
usePostById.tsts
import {ReactQueryOptions ,RouterInputs ,trpc } from './trpc';typePostByIdOptions =ReactQueryOptions ['post']['byId'];typePostByIdInput =RouterInputs ['post']['byId'];functionusePostById (input :PostByIdInput ,options ?:PostByIdOptions ) {returntrpc .post .byId .useQuery (input ,options );}
Infer abstract types from a "Router Factory"
If you write a factory which creates a similar router interface several times in your application, you may wish to share client code between usages of the factory. @trpc/react-query/shared
exports several types which can be used to generate abstract types for a router factory, and build common React components which are passed the router as a prop.
api/factory.tstsx
import {t ,publicProcedure } from './trpc';// @trpc/react-query/shared exports several **Like types which can be used to generate abstract typesimport {RouterLike ,UtilsLike } from '@trpc/react-query/shared';// Factory function written by you, however you need,// so long as you can infer the resulting type of t.router() laterexport functioncreateMyRouter () {returnt .router ({createThing :publicProcedure .input (ThingRequest ).output (Thing ).mutation (/* do work */),listThings :publicProcedure .input (ThingQuery ).output (ThingArray ).query (/* do work */),})}// Infer the type of your router, and then generate the abstract types for use in the clienttypeMyRouterType =ReturnType <typeofcreateRouter >exportMyRouterLike =RouterLike <MyRouterType >exportMyRouterUtilsLike =UtilsLike <MyRouterType >
api/factory.tstsx
import {t ,publicProcedure } from './trpc';// @trpc/react-query/shared exports several **Like types which can be used to generate abstract typesimport {RouterLike ,UtilsLike } from '@trpc/react-query/shared';// Factory function written by you, however you need,// so long as you can infer the resulting type of t.router() laterexport functioncreateMyRouter () {returnt .router ({createThing :publicProcedure .input (ThingRequest ).output (Thing ).mutation (/* do work */),listThings :publicProcedure .input (ThingQuery ).output (ThingArray ).query (/* do work */),})}// Infer the type of your router, and then generate the abstract types for use in the clienttypeMyRouterType =ReturnType <typeofcreateRouter >exportMyRouterLike =RouterLike <MyRouterType >exportMyRouterUtilsLike =UtilsLike <MyRouterType >
api/server.tstsx
export typeAppRouter = typeofappRouter ;// Export your MyRouter types to the clientexport type {MyRouterLike ,MyRouterUtilsLike } from './factory';
api/server.tstsx
export typeAppRouter = typeofappRouter ;// Export your MyRouter types to the clientexport type {MyRouterLike ,MyRouterUtilsLike } from './factory';
frontend/usePostCreate.tstsx
import type {MyRouterLike ,MyRouterUtilsLike ,trpc ,useUtils } from './trpc';typeMyGenericComponentProps = {route :MyRouterLike ;utils :MyRouterUtilsLike ;};functionMyGenericComponent (props :MyGenericComponentProps ) {const {route } =props ;constthing =route .listThings .useQuery ({filter : 'qwerty',});constmutation =route .doThing .useMutation ({onSuccess () {props .utils .listThings .invalidate ();},});functionhandleClick () {mutation .mutate ({name : 'Thing 1',});}return; /* ui */}functionMyPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . deep .route .things }utils ={utils . deep .route .things }/>);}functionMyOtherPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . different .things }utils ={utils . different .things }/>);}
frontend/usePostCreate.tstsx
import type {MyRouterLike ,MyRouterUtilsLike ,trpc ,useUtils } from './trpc';typeMyGenericComponentProps = {route :MyRouterLike ;utils :MyRouterUtilsLike ;};functionMyGenericComponent (props :MyGenericComponentProps ) {const {route } =props ;constthing =route .listThings .useQuery ({filter : 'qwerty',});constmutation =route .doThing .useMutation ({onSuccess () {props .utils .listThings .invalidate ();},});functionhandleClick () {mutation .mutate ({name : 'Thing 1',});}return; /* ui */}functionMyPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . deep .route .things }utils ={utils . deep .route .things }/>);}functionMyOtherPageComponent () {constutils =useUtils ();return (<MyGenericComponent route ={trpc . different .things }utils ={utils . different .things }/>);}
A more complete working example can be found here