zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

Genereated Trpc routes does not return types for relations #409

Closed Azzerty23 closed 1 year ago

Azzerty23 commented 1 year ago

Description and expected behavior Generated Trpc routes do not allow for retrieving the types of relationships (include).

Screenshots ✅ With original Prisma client:

Capture d’écran 2023-05-10 à 11 25 43

❌ With generated trpc routes:

Capture d’écran 2023-05-10 à 11 26 52

Environment (please complete the following information):

Additional context When I overwrite the generated procedure...

Capture d’écran 2023-05-10 à 13 10 24

...typing works well

Capture d’écran 2023-05-10 à 13 06 59

But I don't have the solution to dynamically attach types to the procedure input.

Azzerty23 commented 1 year ago

As a workaround, destructuring the input object allows all relations to be present, but as optional.

Capture d’écran 2023-05-10 à 13 52 18
ymc9 commented 1 year ago

Hi @Azzerty23 ,

Thanks for bringing this up. Unfortunately, this is a current limitation of tRPC. Due to the way how tRPC infers types, the router's typing is determined statically and cannot automatically adapt to the input's shape as Prisma could. Here's a github issue about this topic: https://github.com/trpc/trpc/issues/3311.

As suggested in the github discussion, it's possible to wrap another layer of hooks around the trpc router to achieve such kind of typing (pretty much what ZenStack is doing with the @zenstackhq/react plugin for generating react hooks), but that'll introduce more complexity and also strange to use because it doesn't look like using tRPC anymore ...

The workaround you suggested can also be useful, although not ideal. At least you can get autocompletion to work for the relation fields. Maybe we can make that change to the trpc plugin?

Azzerty23 commented 1 year ago

I was not aware of this limitation in tRPC. I understand that you do not want to tweak tRPC. I hope that this issue will be solved through an enhancement of TypeScript and tRPC implementation. In the meantime, having an option to opt-in for the workaround would be great for sure!

ymc9 commented 1 year ago

Cool. Let me think about how to express that "opt-in" 😄.

ymc9 commented 1 year ago

Hi, @Azzerty23 I'm thinking about this issue again, and I feel maybe we can do something to "fix" trpc's typing, by casting its client hooks appropriately. Are you using trpc over Next.js with createTRPCNext now?

Azzerty23 commented 1 year ago

Hi @ymc9, yes, I do. Do you mean you want to improve the typing of AppRouter that is passed to createTRPCNext<AppRouter>?

ymc9 commented 1 year ago

I spent some time poking around trpc's typing and couldn't find a way to hack it on the server-side router definition, but I think we can probably fix it on the trpc client side, since we're doing code generation anyway.

The change may look like this:

import { enhance } from '../routers/generated/next-utils.ts';

const trpc = enhance(createTRPCNext<AppRouter>({
    ...
}));

...

const query = trpc.post.findMany({include: { author: true}});
// query.data has type `Post & { author: User }` then

The enhance function is generated and only does type-casting, turning hooks like findMany etc. into Prisma-style generic typing so that the output's type adapts to the input.

What's unfortunate is the casting is client-specific, so I guess separate code needs to be generated for different client frameworks. Haven't looked deeply into this yet.

Does this make sense to you in general?

Azzerty23 commented 1 year ago

I see, indeed it seems to be the best approach!

ymc9 commented 1 year ago

Thanks! I'll continue exploring this route then.

ymc9 commented 1 year ago

Hi @Azzerty23 , this has been added in the latest "beta.3" release.

https://zenstack.dev/docs/reference/plugins/trpc#client-helpers