Typed wrappers for procedures

I have a TRPC client with working queries and mutations. I wanted to create wrapper functions for all the procedure so that instead of trpc.someQuery.query(...) I can use someQuery(...), and instead of trpc.someMutation.mutate(...), someMutation(...). I'm having trouble with getting the wrapped functions to have correct parameter and return types. Currently I have:
function wrap<F extends ((...args: any[]) => any)>(fnWithClient: (c: typeof client) => F): (...args: Parameters<F>) => ReturnType<F> {
return (...args: Parameters<F>) => fnWithClient(getClient())(...args);
}
export const someQuery = wrap((client) => client.someQuery.query)
export const someMutation = wrap((client) => client.someMutation.mutation)
function wrap<F extends ((...args: any[]) => any)>(fnWithClient: (c: typeof client) => F): (...args: Parameters<F>) => ReturnType<F> {
return (...args: Parameters<F>) => fnWithClient(getClient())(...args);
}
export const someQuery = wrap((client) => client.someQuery.query)
export const someMutation = wrap((client) => client.someMutation.mutation)
It works in run time, and even shows correct types in VSCode, but when I generate a .d.ts, it says these functions have type (input?: unknown, options?: ProcedureOptions | undefined) => Promise<unknown>. How can I fix this issue, and is there a more elegant way to create such wrapper functions? I would prefer to use something like export const someQuery = wrap('someQuery').
T
trash385d ago
i wonder if this is what happens when you try to leverage types that are internal to the package, i have tried myself though tbh @julius does that sound right? just guessing
J
julius385d ago
Maybe you can get some inspiration from the withQuery() I did for cal.com https://github.com/calcom/cal.com/blob/446c29dd9c576103d7b3caa02317a65b43db0e9d/apps/web/lib/QueryCell.tsx#L86
GitHub
cal.com/QueryCell.tsx at 446c29dd9c576103d7b3caa02317a65b43db0e9d ·...
Scheduling infrastructure for absolutely everyone. - cal.com/QueryCell.tsx at 446c29dd9c576103d7b3caa02317a65b43db0e9d · calcom/cal.com
H
hagabaka385d ago
Would AnyQueryProcedure include the type of trpc.someQuery?
H
hagabaka385d ago
I don't understand DecorateQuery used in that function. Seems to be this gigantic type defined here https://github.com/trpc/trpc/blob/19c7c27d8ed548b2bc7ab5eb921fd179143aa230/packages/react-query/src/createTRPCReact.tsx#L87
GitHub
trpc/createTRPCReact.tsx at 19c7c27d8ed548b2bc7ab5eb921fd179143aa23...
🧙‍♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy. - trpc/createTRPCReact.tsx at 19c7c27d8ed548b2bc7ab5eb921fd179143aa230 · trpc/trpc
J
julius385d ago
DecorateProcedure is the type of like trpc.post.byId yes you're extending AnyProcedure - it will get narrowed on invocation
H
hagabaka385d ago
When I try to assign const a: AnyQueryProcedure = client.someQuery, it says it is missing properties _def, _type, and _procedure I'm justing createTRPCProxyClient, not the with react
J
julius385d ago
so there's a similar type for the vanilla client - so that shouldn't be a problem why are you giving it the type implicitely? also - can you tell a bit more about the usecase? why do you want to do this?
const query = wrap(c => c.post.byId);
const data = query({ id: 1 });
const query = wrap(c => c.post.byId);
const data = query({ id: 1 });
H
hagabaka385d ago
I have a mini library that used to have only functions that make fetch calls, and now I'm adding an TRPC API. I want to keep the exports consistent so prefer to export functions for the individual procedures instead of a TRPC client. Also I want the client to be lazily created when any of the procedures is used.
N
Nick385d ago
Isn't this basically it?
function makeWrap<T>(t: T) {
return function wrap<Q>(func: (t: T) => Q) {
return func(t)
}
}

const wrap = makeWrap(trpcClient)
const someId = 1
wrap(c => c.post.byId.query(someId))
function makeWrap<T>(t: T) {
return function wrap<Q>(func: (t: T) => Q) {
return func(t)
}
}

const wrap = makeWrap(trpcClient)
const someId = 1
wrap(c => c.post.byId.query(someId))
Not exactly sure what's to be gained by using tRPC types in the implementation here, it would be useful to see a more complete example so we can advise
More Posts
Are TRPC server procedures actual endpoints? Meaning can you directly do a `post` request to them?Lets say you have a public procedure called `getHelloWorld`, can you hit it by doing `localhost:3000TRPCClientError - No "query"-procedure on path "user.all"Im using react native expo, prisma, trpc and the postgres database is on railway I have run the follAm I the only one struggling with pnpm + TypeScript monorepo + trpc?Hello all, When using pnpm in a TypeScript monorepo without `node-linker`, I hit those errors: ```tRPC standalone server in monorepoHi, I'm using t3-stack monorepo as my base and I've swapped out NextJS backend for standalone HTTP Codemod to v10 is not modifying any fileHello 👋, I must be super dumb but running `pnpm dlx trpc-v10-migrate-codemod ` in my project isn't No overload matches this call when outputting unionsHello there 👋, I have this simple procedure (we're not fully migrated on v10 yet, using interop): [help] Uncaught (in promise) TRPCClientError: Property description must be an object: uAfter building on linux, I visit the site. And Chrome console shows this error. But if I build on myHow can I make tRPC+NextJs APIs faster? (db and functions region is already same)Hi, I have migrated my website backend (https://clubofcoders.com) from NestJs + Prisma + Cloud Run tThrowing fastify errors when using fastify adapterHello, I'm using `fastifyTRPCPlugin` from `@trpc/server/adapters/fastify` and trying to throw errorsConfused about createProxySSGHelpersIf you can use this helper inside of `getServerSideProps` without having `ssr: true` what is the difHow to check if data is being prefetched?What is a method to check if ssg prefetching actually occurs? Through the network tab?How can I access ctx from inside of a procedure?``` const appRouter = t.router({ helloTab: t.procedure.input(z.object({ url: z.string().url() })).Async User Call in `createContext` (context.ts) or in `isAuthed` (in trpc.ts)Hi all! Should I be getting the user in all requests via createContext in the following async call `'req' of undefined in onError of express middlewareI've recently noticed that I get a bunch of errors regarding req object missing in ctx for onError pMutations and Queries in React Contexts causing unexpected behaviorsIn my organization, we recently moved to put all of our mutations/queries into React Contexts and ouCustom error managementHey peeps! I could've sworn I created a GitHub issue about this, but I must've been dreaming, becauscontext questionWhy are the context examples only showing opinionated examples with next/react auth ? Also i find itasync middlewareis it possible to define an async middleware? I want to do something like this but it throws errors The type of the second route of the nested route is neverhttps://github.com/StringKe/nx-mulit-trpc-type-error/blob/main/apps/app1/src/pages/index.tsx#L12errorFormatter ignored when using appRouter.createCallerMy errorFormatter works correctly in the actual application using an adapter, e.g. ``` trpcExpress.