yeetcode.io
yeetcode.io4mo ago

My TRPC hooks are getting typed as `any`

I'm using a Typescript + Express backend (Node.js, version 18), and a React Native (Typescript) frontend. For some reason by TRPC tanstack-query hooks don't seem to be typing things correctly. I am trying to understand why. I have a monorepo setup with a file structure like this: root -frontend -backend So the frontend and backend files can import from each other, and everything lives under one .git in the root. In my backend, I create a router and export the type:
const appRouter = router({
myName1: myRouter1,
myName2: myRouter2,
});

export type AppRouter = typeof appRouter;
const appRouter = router({
myName1: myRouter1,
myName2: myRouter2,
});

export type AppRouter = typeof appRouter;
Here is an example typing I get when I hover over a procedure in one of my subrouters. I don't return any in any of my procedures.
const myProcedureName: QueryProcedure<{
input: number;
output: ({
author: {
id: number;
};
} & {
myDataField: number;
})[];
}>
const myProcedureName: QueryProcedure<{
input: number;
output: ({
author: {
id: number;
};
} & {
myDataField: number;
})[];
}>
In my React Native app, I import the type:
import {createTRPCReact} from '@trpc/react-query';
import type {AppRouter} from 'my/file/path/to/backend';
export const trpc = createTRPCReact<AppRouter>();
import {createTRPCReact} from '@trpc/react-query';
import type {AppRouter} from 'my/file/path/to/backend';
export const trpc = createTRPCReact<AppRouter>();
Then in my App.tsx, I create the trpcClient:
const trpcClient = trpc.createClient({
links: [
httpBatchLink({
url: `${API_URL}/trpc`,
}),
],
});
const trpcClient = trpc.createClient({
links: [
httpBatchLink({
url: `${API_URL}/trpc`,
}),
],
});
Now when I use a hook:
// useProfile.ts
export default function useProfile(id: number) {
return trpc.user.myProcedureName.useQuery(id);
}

//MyComponent.ts
function Component() {
const {data} = useProfile(id);
// useProfile.ts
export default function useProfile(id: number) {
return trpc.user.myProcedureName.useQuery(id);
}

//MyComponent.ts
function Component() {
const {data} = useProfile(id);
My data gets typed as any, what am I doing wrong in my setup?
5 Replies
yeetcode.io
yeetcode.io4mo ago
I've managed to distill the issue even further: When I make this procedure on the backend:
const getPostsByUser = protectedProcedure
.input(z.number())
.query(async ({ input: targetId, ctx }) => {
return "HELLO" as const;
});
const getPostsByUser = protectedProcedure
.input(z.number())
.query(async ({ input: targetId, ctx }) => {
return "HELLO" as const;
});
Then my frontend hook data field gets typed correctly. But if I use a prisma query:
const getPostsByUser = protectedProcedure
.input(z.number())
.query(async ({ input: targetId, ctx }) => {
return await myPrismaQuery();
});
const getPostsByUser = protectedProcedure
.input(z.number())
.query(async ({ input: targetId, ctx }) => {
return await myPrismaQuery();
});
My frontend hook data field gets typed as any. Why is this happening? My prisma query is certainly not returning type any.
yeetcode.io
yeetcode.io4mo ago
Here is an image of the return type of my prisma query.
No description
yeetcode.io
yeetcode.io4mo ago
What's even weirder is if I cast the return type:
const record = await myPrismaQuery();
return record as number; // invalid cast
const record = await myPrismaQuery();
return record as number; // invalid cast
Then my frontend data gets typed correctly as number | undefined. But if I remove the cast, turning it into the typing as pictured above, then the frontend starts getting any.
yeetcode.io
yeetcode.io4mo ago
I got it fixed by following this four year old twitter thread: https://x.com/colinhacks/status/1298030688063561728?lang=en
Colin McDonnell (@colinhacks) on X
"nohoist" is literally not documented anywhere except in the blog post where it was introduced https://t.co/SuobFbSq4z
Twitter
yeetcode.io
yeetcode.io4mo ago
Is there a reason this isn't listed in the docs anywhere (or did I miss it?). It seems like it should be a pretty common issue given how prevalent prisma is. I get it isn't an issue with TRPC per se, but it does seem like it could have a useful place here. I'd be happy to make a docs contribution.