メインコンテンツへスキップ
バージョン: 11.x

タイプの推論

@trpc/server によって可能になった型推論に加えて(こちらを参照)、この統合では React でのみ使用するためのいくつかの推論ヘルパーも提供されます。

ルーターに基づいて React Query オプションを推論する

tRPC プロシージャの周りにカスタムフックを作成する場合、ルーターからオプションの型を推論する必要がある場合があります。@trpc/react-query からエクスポートされた inferReactQueryProcedureOptions ヘルパーを使用して行うことができます。

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);
}

"ルーターファクトリ" から抽象型を推論する

アプリケーションで同様のルーターインターフェイスを複数回作成するファクトリを作成する場合、ファクトリの使用間でクライアントコードを共有したい場合があります。@trpc/react-query/shared は、ルーターファクトリの抽象型を生成し、ルーターを小道具として渡される共通の React コンポーネントを構築するために使用できるいくつかの型をエクスポートします。

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}
/>
);
}

こちらでより完全な作業例を確認できます。