본문 바로가기
버전: 10.x

타입 추론

비공식 베타 번역

이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →

@trpc/server에서 제공하는 타입 추론(여기 참조)에 더해, 이 통합(React용)은 순수하게 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는 라우터 팩토리에 대한 추상 타입을 생성하고, 라우터를 prop으로 전달받는 공통 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}
/>
);
}

더 완벽한 실제 구현 예제는 여기에서 확인할 수 있습니다