Aller au contenu principal
Version : 11.x

Inférence de types

Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

En complément de l'inférence de types offerte par @trpc/server (voir ici), cette intégration propose également des utilitaires d'inférence spécifiquement conçus pour React.

Inférer les options de React Query à partir de votre routeur

Lorsque vous créez des hooks personnalisés autour des procédures tRPC, il est parfois nécessaire d'inférer automatiquement les types des options à partir du routeur. Vous pouvez y parvenir via l'utilitaire inferReactQueryProcedureOptions exporté par @trpc/react-query.

trpc.ts
ts
import {
createTRPCReact,
type inferReactQueryProcedureOptions,
} from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import type { AppRouter } from './server';
 
// infer the types for your router
export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;
 
export const trpc = createTRPCReact<AppRouter>();
trpc.ts
ts
import {
createTRPCReact,
type inferReactQueryProcedureOptions,
} from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import type { AppRouter } from './server';
 
// infer the types for your router
export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;
 
export const trpc = createTRPCReact<AppRouter>();
usePostCreate.ts
ts
import {
trpc,
type ReactQueryOptions,
type RouterInputs,
type RouterOutputs,
} from './trpc';
 
type PostCreateOptions = ReactQueryOptions['post']['create'];
 
function usePostCreate(options?: PostCreateOptions) {
const utils = trpc.useUtils();
 
return trpc.post.create.useMutation({
...options,
onSuccess(post) {
// invalidate all queries on the post router
// when a new post is created
utils.post.invalidate();
options?.onSuccess?.(post);
},
});
}
usePostCreate.ts
ts
import {
trpc,
type ReactQueryOptions,
type RouterInputs,
type RouterOutputs,
} from './trpc';
 
type PostCreateOptions = ReactQueryOptions['post']['create'];
 
function usePostCreate(options?: PostCreateOptions) {
const utils = trpc.useUtils();
 
return trpc.post.create.useMutation({
...options,
onSuccess(post) {
// invalidate all queries on the post router
// when a new post is created
utils.post.invalidate();
options?.onSuccess?.(post);
},
});
}
usePostById.ts
ts
import { ReactQueryOptions, RouterInputs, trpc } from './trpc';
 
type PostByIdOptions = ReactQueryOptions['post']['byId'];
type PostByIdInput = RouterInputs['post']['byId'];
 
function usePostById(input: PostByIdInput, options?: PostByIdOptions) {
return trpc.post.byId.useQuery(input, options);
}
usePostById.ts
ts
import { ReactQueryOptions, RouterInputs, trpc } from './trpc';
 
type PostByIdOptions = ReactQueryOptions['post']['byId'];
type PostByIdInput = RouterInputs['post']['byId'];
 
function usePostById(input: PostByIdInput, options?: PostByIdOptions) {
return trpc.post.byId.useQuery(input, options);
}

Inférer des types abstraits depuis une "Router Factory"

Si vous implémentez une fabrique qui crée plusieurs fois une interface de routeur similaire dans votre application, vous pourriez vouloir partager du code client entre les différentes instances. @trpc/react-query/shared exporte plusieurs types permettant de générer des types abstraits pour une fabrique de routeurs, et de construire des composants React génériques qui reçoivent le routeur en tant que prop.

api/factory.ts
tsx
import { t, publicProcedure } from './trpc';
 
// @trpc/react-query/shared exports several **Like types which can be used to generate abstract types
import { 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() later
export function createMyRouter() {
return t.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 client
type MyRouterType = ReturnType<typeof createMyRouter>
export MyRouterLike = RouterLike<MyRouterType>
export MyRouterUtilsLike = UtilsLike<MyRouterType>
api/factory.ts
tsx
import { t, publicProcedure } from './trpc';
 
// @trpc/react-query/shared exports several **Like types which can be used to generate abstract types
import { 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() later
export function createMyRouter() {
return t.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 client
type MyRouterType = ReturnType<typeof createMyRouter>
export MyRouterLike = RouterLike<MyRouterType>
export MyRouterUtilsLike = UtilsLike<MyRouterType>
api/server.ts
tsx
export type AppRouter = typeof appRouter;
 
// Export your MyRouter types to the client
export type { MyRouterLike, MyRouterUtilsLike } from './factory';
api/server.ts
tsx
export type AppRouter = typeof appRouter;
 
// Export your MyRouter types to the client
export type { MyRouterLike, MyRouterUtilsLike } from './factory';
frontend/usePostCreate.ts
tsx
import type { MyRouterLike, MyRouterUtilsLike, trpc, useUtils } from './trpc';
 
type MyGenericComponentProps = {
route: MyRouterLike;
utils: MyRouterUtilsLike;
};
 
function MyGenericComponent(props: MyGenericComponentProps) {
const { route } = props;
const thing = route.listThings.useQuery({
filter: 'qwerty',
});
 
const mutation = route.doThing.useMutation({
onSuccess() {
props.utils.listThings.invalidate();
},
});
 
function handleClick() {
mutation.mutate({
name: 'Thing 1',
});
}
 
return; /* ui */
}
 
function MyPageComponent() {
const utils = useUtils();
 
return (
<MyGenericComponent
route={trpc.deep.route.things}
utils={utils.deep.route.things}
/>
);
}
 
function MyOtherPageComponent() {
const utils = useUtils();
 
return (
<MyGenericComponent
route={trpc.different.things}
utils={utils.different.things}
/>
);
}
frontend/usePostCreate.ts
tsx
import type { MyRouterLike, MyRouterUtilsLike, trpc, useUtils } from './trpc';
 
type MyGenericComponentProps = {
route: MyRouterLike;
utils: MyRouterUtilsLike;
};
 
function MyGenericComponent(props: MyGenericComponentProps) {
const { route } = props;
const thing = route.listThings.useQuery({
filter: 'qwerty',
});
 
const mutation = route.doThing.useMutation({
onSuccess() {
props.utils.listThings.invalidate();
},
});
 
function handleClick() {
mutation.mutate({
name: 'Thing 1',
});
}
 
return; /* ui */
}
 
function MyPageComponent() {
const utils = useUtils();
 
return (
<MyGenericComponent
route={trpc.deep.route.things}
utils={utils.deep.route.things}
/>
);
}
 
function MyOtherPageComponent() {
const utils = useUtils();
 
return (
<MyGenericComponent
route={trpc.different.things}
utils={utils.different.things}
/>
);
}

Un exemple de travail plus complet est disponible ici