[SOLVED] Object relation works when running app but doesn't compile to TypeScript?
My database schema looks as follows:
Meanwhile on my client when I do:
I get the following TypeScript error under task.
category
.name:
Property 'category' does not exist on type 'GetResult<{ id: number; description: string; isDone: boolean; userId: number | null; categoryId: number; }, unknown> & {}'. Did you mean 'categoryId'?ts(2551)
I have seen examples within the Wasp repo that allow this to work.
This is done by using the includes
part of the ORM like so:
However despite this, it still seems like I am missing a trick to get the type safety to understand that a Task
is expected to reference Category
(object) as well as the CategoryId
?
This is also blocking me from successfully deploying to Fly.io
Thanks11 Replies
Thanks for reporting this @KYAN1TE , we will take a look into it! @miho @Filip do you have any ideas what might be causing this issue?
No worries, here is the repo btw: https://github.com/karam94/WaspTodoApp
Hi @KYAN1TE, I can try to run your repro repo and test a solution later, but I think I know the fix right away. Let me know if it works. I'll dig deeper if not 🙂
TL;DR: Use the
satisfies
keyword.
The problem
You annotated the Query with GetAllUserTasksQuery<void, Task[]>
which tells Wasp "This query doesn't receieve any arguments and returns an array of Task
objects."
An object of type Task
truly doesn't contain the Category
. So, strictly speaking, the error is correct.
The solution
I'm guessing that you want TypeScript to infer the correct return type from the findMany
call.
If so, instead of annotating the query with GetAllUserTasksQuery<void, Task[]>
, try using the satisfies
keyword. Like this:
This tells TypeScript: "Make sure this function doesn't take any arguments and works with the proper context
object, but infer the correct return type on your own."Our docs used to mention this, but we removed it thinking it was too much of an edge case. Here's the relevant section from the old docs:
Thanks for the response @Filip
Unfortunately, I still getting an error on the client/JSX code for
task.category.name
despite applying your recommended changes to the getAllUserTasksQuery
.
I believe this is simply because despite the change on the server, my React component's prop expects a type Task
(which by default doesn't contain the category object, only the id) & so my next question would be, in this case, how are we expected to match types between server & client in this case?
Kind of feel like unless there is an obvious solution for this that I'm missing, that it makes it a bit difficult to pass queried data down as typed props & that there is an expectation to always query data in the component where it is required, which makes it difficult to build front-ends up as different reusable components 🤔
ThanksWohooo @KYAN1TE, you just became a Waspeteer level 3!
So I've fixed it by having a play.
Created a
types.ts
in the server with:
& then I just use that within my getAllUserTasksQuery
without satisfies
like so:
& then that lets me define my client props like so to avoid the error client side:
Note that I'm a C# guy, not a TypeScript guy & I don't know much about wasp (yet) so I am all ears if there is a better/more maintainable way to do this.
Thanks
Another update, so the Fly deployment with the above supposed solution isn't functional:
It's pretty self explanatory & understandable if it's trying to deploy client/server separately (unsure exactly how wasp is compiling then deploying under the hood) but as it's late, I'll not bother trying to solve (except the obvious of just having two separate types on server & client which has dedployed successfully) & just see what you suggest tomorrow morning 🙂 Thanks againHey @KYAN1TE,
First of all, massive props for documenting and explaining the problem perfectly!
It's always a joy helping users who put an effort into communication (and they're not exactly a common occurance 😅).
I'll make sure to take a deep dive into this first thing tomorrow!
I believe this is simply because despite the change on the server, my React component's prop expects a type TaskThis is correct. You'd have to tell the component to except something else (i.e., a
Task
object that expects a category), which is what you did.
how are we expected to match types between server & client in this case?Ideally, Wasp would expose types for all possible objects different Prisma queries can return. Unfortunately, this would amount to an almost infinite amount of types, so we're still figuring out how to support something like that 😅 With that in mind, our current options are: - Option 1: Use the Query's return type as a source of truth and rely on type inference for typing the client stuff. - Option 2: Explicitly define the payload type in a single place and import/reuse it on both the client and the server. - Option 3: Define different types on the server and on the client. You attempted options 1 and 2, but the code wouldn't compile. You then successfully implemented option 3. Let's try to figure out what went wrong with the first two. Option 1 Gist link: https://gist.github.com/sodic/211a5e719163505e4d0c5dbb8d50d693. The gist contains all the changed files. You can delete
types.ts
on the server.
Option 2
Coming in a bit 🙂Amazing, thank you so much @Filip! I look forward to option 2 but can live with having to use
satisfies
for now 👍Option 2
Hey, finally got around to fixing up option 2: https://gist.github.com/sodic/79baf87800ab1a485ab6b6551fb40956
In short, for sharing files between the server and the client, you can use the
shared
folder (we mention it here: https://wasp-lang.dev/docs/tutorial/project-structure).
Your IDE will report an import error in src/shared/types.ts
, but you can ignore it. It won't come up during the build. This is a mistake on our side, thanks for sticking with us regardless of these rough edges 🙃).
Extra stuff
If you're annoyed by the red squiggly line, you can update the paths
field in src/shared/tsconfig.json
to fix it:
I won't go into detail about what's going on here, but the short version is:
This false positive import error is a bug on our side.
We had to choose whether we want false positives or false negatives in the IDE. We choose to go with false positives.
You can instead opt for false negatives by implementing the tsconfig
outlined above. Just be careful: by doing so you might lose compile-time reports for some real type errors.Thank you 🙂