T
tRPC

❓-help

Reusable Component to take router as props / dependency injection. How to type?

BBillyBob2/6/2024
for example:
export const Content = async ({ api }) => {
const items = await api.getAll.query({ watched: true })

if (!items) {
return <EmptyState />
}

return (
<CardsContainer>
{items.map((i) => {
return <Card key={i.id} imgSrc={buildImgSrc(i.posterPath)} {...i} />
})}
</CardsContainer>
)
}
export const Content = async ({ api }) => {
const items = await api.getAll.query({ watched: true })

if (!items) {
return <EmptyState />
}

return (
<CardsContainer>
{items.map((i) => {
return <Card key={i.id} imgSrc={buildImgSrc(i.posterPath)} {...i} />
})}
</CardsContainer>
)
}
Content is either movies or series. I have movieRouter and seriesRouter with the same procedures. How can i type api ?
Nnlucas2/6/2024
You linked to the blog post I wrote on this right? The answer is the second half to that If you have any more specific questions I can try to help but this is a broad one
BBillyBob2/6/2024
No description
BBillyBob2/6/2024
This expression is not callable.
Each member of the union type '(<T extends MovieFindManyArgs<DefaultArgs>>(args?: SelectSubset<T, MovieFindManyArgs<DefaultArgs>> | undefined) => PrismaPromise<...>) | (<T extends SerieFindManyArgs<...>>(args?: SelectSubset<...> | undefined) => PrismaPromise<...>)' has signatures, but none of those signatures are compatible with each other.
This expression is not callable.
Each member of the union type '(<T extends MovieFindManyArgs<DefaultArgs>>(args?: SelectSubset<T, MovieFindManyArgs<DefaultArgs>> | undefined) => PrismaPromise<...>) | (<T extends SerieFindManyArgs<...>>(args?: SelectSubset<...> | undefined) => PrismaPromise<...>)' has signatures, but none of those signatures are compatible with each other.
Hi @Nick Lucas Thanks for responding. I am not sure how to solve this type issue.
Nnlucas2/6/2024
If you can put together a stackblitz example then I could take a look. It’s typescript foo though so if you don’t understand the solution then you’re going to be in trouble down the line Should be possible anyway
BBillyBob2/6/2024
hm, i use typescript and have for a couple of years, but if its messy for the sake of readability i might need another solution. I was trying to create a reuseable createService
import { type Prisma, PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

type CreateFunction<T> = (data: T) => Promise<T>
type GetAllFunction<T> = () => Promise<T[]>
type GetByIdFunction<T> = (id: number) => Promise<T | null>
type DeleteFunction<T> = (id: number) => Promise<T | null>
type UpdateFunction<T> = (id: number, data: T) => Promise<T | null>

interface EntityService<T> {
create: CreateFunction<T>
getAll: GetAllFunction<T>
getById: GetByIdFunction<T>
delete: DeleteFunction<T>
update: UpdateFunction<T>
}

const createService = <T>( // This line?
modelName: Uncapitalize<Prisma.ModelName>,
): EntityService<T> => {
const prismaModel = prisma[modelName]

return {
create: (data) => prismaModel.create({ data }),
getAll: () => prismaModel.findMany(),
getById: (id) => prismaModel.findUnique({ where: { id } }),
delete: (id) => prismaModel.delete({ where: { id } }),
update: (id, data) => prismaModel.update({ where: { id }, data }),
}
}

// Usage
const movieService = createService<Prisma.MovieCreateInput>('movie')
const serieService = createService<Prisma.SerieCreateInput>('serie')
import { type Prisma, PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

type CreateFunction<T> = (data: T) => Promise<T>
type GetAllFunction<T> = () => Promise<T[]>
type GetByIdFunction<T> = (id: number) => Promise<T | null>
type DeleteFunction<T> = (id: number) => Promise<T | null>
type UpdateFunction<T> = (id: number, data: T) => Promise<T | null>

interface EntityService<T> {
create: CreateFunction<T>
getAll: GetAllFunction<T>
getById: GetByIdFunction<T>
delete: DeleteFunction<T>
update: UpdateFunction<T>
}

const createService = <T>( // This line?
modelName: Uncapitalize<Prisma.ModelName>,
): EntityService<T> => {
const prismaModel = prisma[modelName]

return {
create: (data) => prismaModel.create({ data }),
getAll: () => prismaModel.findMany(),
getById: (id) => prismaModel.findUnique({ where: { id } }),
delete: (id) => prismaModel.delete({ where: { id } }),
update: (id, data) => prismaModel.update({ where: { id }, data }),
}
}

// Usage
const movieService = createService<Prisma.MovieCreateInput>('movie')
const serieService = createService<Prisma.SerieCreateInput>('serie')
Nnlucas2/6/2024
Yeah I have several of these at work, we have about 25 generated routers. It’s a good pattern once you crack the generics stuff
BBillyBob2/6/2024
i can put together a stackblitz no problem
Nnlucas2/6/2024
I don’t use Prisma though so I’d need to have a play with a dummy version 😇
BBillyBob2/6/2024
yeah i was trying to find some base Prisma delegate verison const prismaModel: Prisma.MovieDelegate<DefaultArgs> | Prisma.SerieDelegate<DefaultArgs> | Prisma.UserDelegate<DefaultArgs> to extend from but cannot find anything
Nnlucas2/6/2024
Sometimes you have to F12 into the declarations and really understand what to use that way Prisma must have some common type you can extend from
BBillyBob2/6/2024
thats what i was hoping for but cant find it but im very rusty with TS too, had a year off. maybe you can see.
Nnlucas2/6/2024
What about “keyof prisma” If you get the model by key then having a generic key is likely enough to calculate your return type and get the concrete model
BBillyBob2/6/2024
does this work? https://stackblitz.com/~/github.com/lwears/ReelScore checking this hm no i need to fix the stackblitz hm, seems prisma cannot run in a webcontainer / stackblitz
Nnlucas2/6/2024
That’s usually okay, we’re looking at types anyway Afraid I’m at work without access for now though so I’ll need to check it out later tonight
BBillyBob2/6/2024
no problem, any help appreciated Tried this but still getting the error:
interface Model {
movie: Movie // Prisma Movie type
serie: Serie // Prisma serie type
user: User
}

type ModelName = keyof Model

const createService = (
modelName: ModelName,
): EntityService<Model[ModelName]> => {
const prismaModel = prisma[modelName]
return {
create: (data) => prismaModel.create({ data }),
getAll: () => prismaModel.findMany(),
getById: (id) => prismaModel.findUnique({ where: { id } }),
delete: (id) => prismaModel.delete({ where: { id } }),
update: (id, data) => prismaModel.update({ where: { id }, data }),
}
}
interface Model {
movie: Movie // Prisma Movie type
serie: Serie // Prisma serie type
user: User
}

type ModelName = keyof Model

const createService = (
modelName: ModelName,
): EntityService<Model[ModelName]> => {
const prismaModel = prisma[modelName]
return {
create: (data) => prismaModel.create({ data }),
getAll: () => prismaModel.findMany(),
getById: (id) => prismaModel.findUnique({ where: { id } }),
delete: (id) => prismaModel.delete({ where: { id } }),
update: (id, data) => prismaModel.update({ where: { id }, data }),
}
}
To get the types in stackblitz you need to have a CORS enabling extension installed. CD to apps/api npx prisma generate
BBillyBob2/6/2024
GitHub
StackBlitz Webcontainer: Prisma fails in multiple ways · Issue #718...
Prisma can be installed in the new StackBlitz Webcontainers with a small workaround of installing a Chrome extension that disables CORS: #7185 (comment) Then you can: Go to https://stackblitz.com/e...
Nnlucas2/6/2024
Yeah this is fairly difficult because they really don't have some generic base class for a Delegate do they? It's definitely possible, just will end up fairly explicit
Nnlucas2/6/2024
So you'll end up needing to define your own MyCrudRepository<T> which implements a handful of methods over a given model, and then you type this router with extends MyCrudRepository<TEntity>
BBillyBob2/6/2024
ok i think i understand. will give it a shot thanks to be honest it might just be a little too complicated for what i am trying to achieve. I switched from Web Dev to CyberSec a year ago. I'm going to switch back so just want something on my github i can show to recruiters I appreciate your time and help though
Nnlucas2/6/2024
No worries!

Looking for more? Join the community!

Recommended Posts
tRPC mutate call firing two requests with custom linkNode: 18.16 tRPC: 10.38.0 pnpm What's wrong with this custom link that's causing it's addition to aIssue with Fastify / tRPC / AngularWe are trying to setup Angular project with tRPC. In Angular we get following error: ``` Error: nodDrizzle query not working only inside trpcMy drizzle query works inside a regular nextjs api route. The same query running inside trpc throws Server freezes when doing mutations...I have the exact same issue as mentioned in this post: https://discord-questions.trpc.io/m/117697170Create Wrapper only for Procedures that support Infinite QueryGreetings, I'm attempting to create a help that will handle some generic logic I desire for a seriWhy am I getting 'Argument type is not assignable to parameter type ProcedureResolver<unknown>'?I have this warning in my editor (jetbrains InteliJ): ``` Argument type () => any[] is not assignabEfficient way to use tRPC client with auth headers from secure storageWondering if anyone has a recommended pattern on caching the deviceId / authHeader using a React ConUsing tRPC with Expo API Routes feature?Is there a possibility to merge "tRPC Express Adapter" with "Expo API Route Express Deployment"? tRTRPC not working on multi tenant appEverything works on localhost. When I deploy it on the vercel None of the mutations work. Every qTRPCClientError: Unable to transform response from serverHi 🙂 I've just started - so nothing more than boiler plate code but for some reason it doesn't workoptimistic updates tRPC v11 + TanStack Query v5I am reading https://tanstack.com/query/latest/docs/framework/react/guides/optimistic-updates#if-theT3 Stack TRPC used in Server ActionsIs there issues using the server calls of TRPC in a nextjs server action? I am seeing weird issues wHow do I setup subscriptions with websockets in Next.js 14 app router?All I've found were some older examples for the pages router which for me were not very understandabWhy is my tRPC + Next 14 (app router) data fetching pattern not refreshing the UI?### Goals of this post: - to know why my UI is not refreshing after i mutate the backend - tUsing tRPC in Next.js MiddlewareHello, I am quite new to tRPC so forgive me if I'm asking something quite obvious/dumb. I was introneed help refreshing websocketWe currently are using tRPC w/ react and websockets. We’re using the URL of the websocket as the autrouter is crashing when in separate fileWhen i use router merging and have e.g users router in separate file, i import router from trpc.ts aHow do I pass a Generic to a trpc query procedure?I want to to something like this: ```ts type AppIdsWithConfig = typeof kodixCareAppId | typeof calenIs there something to be done about trpc errors and solidjs/seroval?Basically if you `throw error` in trpc route, solidjs seroval fails to serialize it during SSR. I doHow can i createCaller from a NextJs App Router if my server uses express tRPC adapter?I'm using the express adapter for the server side of tRPC, and the client is a NextJS AppRouter app.