Dynamically type the data result of a hook according to inputs #2150
-
Hey, folks! We ran into a hiccup with trying to dynamically type the data that comes back from our endpoint. Imagine an identity endpoint that can return either a string or a number: // I recognize that you probably wouldn't do actually want to do this
// This is only an example to setup for our more complex real world example
const router = createRouter().query("foo", {
input: z.enum(["string", "number"]),
resolve: async ({input}) => {
const pickEm = {
string "test",
number: 42
}
return pickEm[input]
}
}) Now, when we go to use this on the frontend: const query = trpc.useQuery(["foo", "string"])
query.data // Inferred type is number | string | undefined
// I would love for this hook have an inferred type of string const query = trpc.useQuery(["foo", "number"])
query.data // Inferred type is number | string | undefined
// I would love for this hook have an inferred type of number That's my simple, silly example to demonstrate the idea of what we're after. // trials/get is an endpoint that takes inputs for Prisma includes or selects for the Trial model
const query = trpc.useQuery(["trials/get", { select: { judgeName: true } } ])
query.data // Has no idea about the select, simply types for the whole Trial model And here is our custom hook that we hacked together to resolve our problem. export const useTrial = <T extends Prisma.TrialSelect>({
trialId,
select
}: {
trialId: string
select: Prisma.Subset<T, Prisma.TrialSelect>
}) => {
type DataPayload = Prisma.TrialGetPayload<{ select: typeof select }>
const query = trpc.useQuery(["trials/get", { id: trialId, select }])
const queryDataTypeFix = query.data as Prisma.TrialSelect
// Fix the data with itself but typed as what we want
query.data = queryDataTypeFix
return query as
| Omit<typeof query, "data"> & {
data: DataPayload
}
} This seems to work well enough to get the types right. But I was surprised there wasn't a more tRPC-ish way (that we could figure out). 100% am willing to contribute if there is a way we think we can do this - although I can't say I'll be too useful actually making the types happen. The TS you guys have drawn up is pretty opaque to me. 🙃 I know with v10 coming, we could be allowed to make some major change if needed to make this reality. tRPC for life, yo! Keep it up! |
Beta Was this translation helpful? Give feedback.
Replies: 10 comments 2 replies
-
I'm unsure if this is possible within the bounds of TS, but I'll look into this. Thanks for the detailed feature request! |
Beta Was this translation helpful? Give feedback.
-
I did indeed figure this was a TypeScript limitation with all the mastery that I saw going on under the hood of tRPC. 😄 No problem, thanks for looking at it! |
Beta Was this translation helpful? Give feedback.
-
Oh! I forgot to add... We're also happy to use a generic if that opens up our use case.
This, of course, is not automagical but it would still do what we needed to do. We did notice that there is already a generic right there where I'm proposing but couldn't figure out how to make it work. We couldn't figure out if that was what it was for. |
Beta Was this translation helpful? Give feedback.
-
I think this would require higher kinded types to work, so maybe one day: microsoft/TypeScript#1213 There are some workarounds involving module augmentation but I'm not sure they'd be practical in this case. |
Beta Was this translation helpful? Give feedback.
-
I'm thinking any sort of generic solution might be impossible because of microsoft/TypeScript#1213 ("Higher Kinded Types"). tRPC already takes in a generic for the function. |
Beta Was this translation helpful? Give feedback.
-
Great minds thinking alike. @mmkal I'd agree that that doesn't seem like something we would want to get into for this. @sachinraja I did notice that generic...But we had no idea what to do with it or if it was going to fit what we wanted to do. The inspiration for this idea came from
Maybe that is what that generic does and we just didn't spend enough time fussing with it to find out? If it is, I'd be happy to add to the docs to make this clear for others. Of course, tRPC is much different than |
Beta Was this translation helpful? Give feedback.
-
So you want to be able to override the type of a |
Beta Was this translation helpful? Give feedback.
-
Leaving this here for reference:
Originally posted by @iduuck in #3311 (comment) |
Beta Was this translation helpful? Give feedback.
-
+1 to this |
Beta Was this translation helpful? Give feedback.
-
still not possible ? |
Beta Was this translation helpful? Give feedback.
I think this would require higher kinded types to work, so maybe one day: microsoft/TypeScript#1213
There are some workarounds involving module augmentation but I'm not sure they'd be practical in this case.