Object relation doesn't compile to TypeScript
I have an explicit many-to-many relation that I want to display data. After migrating from version 0.11 to version 0.12, I can't find a way to display objects of my entity. Here is my schema:
entity Material {=psl
id Int @id @default(autoincrement())
code String @unique
name String
count Int
measurementUnit String
products ProductMaterials[]
psl=}
entity ProductMaterials {=psl
product Product @relation(fields: [productId], references: [id])
productId Int
material Material @relation(fields: [materialId], references: [id])
materialId Int
materialCount Int
measurementUnit String
@@id([productId, materialId])
psl=}
entity Product {=psl
id Int @id @default(autoincrement())
code String @unique
name String
description String
materials ProductMaterials[]
productionPlans ProductionPlanProducts[]
psl=}
When i try to display products for material error occurs: Property 'products' does not exist on type 'GetResult<{ id: number; code: string; name: string; count: number; measurementUnit: string; }, unknown> & {}'.
Since I have migrated from an old version of Wasp, in which my code works, I'm curious about what makes the difference that in the previous version, the import from @wasp/entities
includes objects of entities, and in the new version, the import from wasp/entities
doesn't include them.
I have found a previous post and solution which includes creating a new type. Is there any way to include objects with types from prisma/entities
?38 Replies
Hm @david.fejes this is quite peculiar! We did quite same changes in 0.12, but I don't think we introduced a regression like this on purpose, if that is indeed what it is.
@miho and @Filip will know more about this specific feature so I am pinging them!
When i try to display products for material error occurs: Property 'products' does not exist on type 'GetResult<{ id: number; code: string; name: string; count: number; measurementUnit: string; }, unknown> & {}'.Howdy đź‘‹ Could you please share your actions / queries code? Only the Prisma related parts if you don't want to share everything.
I have found a previous post and solution which includes creating a new type. Is there any way to include objects with types from prisma/entities?Could you please link the post?
Since im overriding CRUD i have created function in tasks.js
export const getMaterials: Materials.GetAllQuery<void, Material[]> = async (args, context) => {
const { Material } = context.entities;
return await Material.findMany({
include: {
products: {
include: {
product: true,
},
},
},
});
};
Here is github link: https://github.com/fejes99/MaterialPlanningApp/blob/main/src/materials/operations/tasks.tsGitHub
MaterialPlanningApp/src/materials/operations/tasks.ts at main · fej...
Contribute to fejes99/MaterialPlanningApp development by creating an account on GitHub.
Wohooo @david.fejes, you just became a Waspeteer level 1!
Here is a link to the post: https://discord.com/channels/686873244791210014/1186410195732140073
So this is an issue with full-stack type safety here 🙂
We use the type you annotated the function with to give you types on the client.
-> In your case it was:
Materials.GetAllQuery<void, Material[]>
-> This says: This function will return a list of Material
(the Material
type has only its types and not the relationships)
You need to annotate it more precisely since you are not returning only a list of Material
but also including the relations which change the type.
👉 The way to do this would be to do:
You see, I'm now combing the basic Material
type with the ProductMaterials
and Product
at places where we have the included relationships.
I know this is annoying! The better behaviour would be to automatically infer the right type and not make you define this complex type.
I've noted this future improvement in this issue: https://github.com/wasp-lang/wasp/issues/1884Thanks!
this should definately be added to the docs ASAP because I was almost giving up on this after almost two days of not understanding why I had to use any types when trying to map stuff inside entities with many to many relations
would this be the correct usage?
@kapa.ai Not sure If it might related, my usecase is implicit many to many relation, with Task and Tag model (1 Tag can belong to multiple Tasks; and one Task can help multiple Tags). The intelisense show no error but the console log denied to compiled:
[ Wasp ] server/operations/actions/index.ts(150,7): error TS2353: Object literal may only specify known properties, and 'Tag' does not exist in type '{ Task: TaskDelegate<DefaultArgs>; }'.
[ Wasp ] server/operations/actions/index.ts(163,7): error TS2353: Object literal may only specify known properties, and 'Tag' does not exist in type '{ Task: TaskDelegate<DefaultArgs>; }'.
[ Wasp ] server/operations/queries/index.ts(89,7): error TS2353: Object literal may only specify known properties, and 'Tag' does not exist in type '{ Task: TaskDelegate<DefaultArgs>; }'.
[ Wasp ] server/operations/queries/index.ts(102,7): error TS2353: Object literal may only specify known properties, and 'Tag' does not exist in type '{ Task: TaskDelegate<DefaultArgs>; }'.
This is due to 4 queries and actions:
- getTasksForTag
- getTagsForTask
- assignTagToTask
- removeTagFromTask
Below is one query:
getTagsForTask:
import { Tag } from 'wasp/entities'
import { type GetTasks } from 'wasp/server/operations'
type GetTagsForTaskPayload = { taskId: string }
export const getTagsForTask: GetTasks<GetTagsForTaskPayload, Tag[]> = async ({ taskId }, context) => { const task = await context.entities.Task.findUnique({ where: { id: taskId }, select: { tags: true }, })
return task?.tags || [] } Obiviously I have already include it in main.wasp: query getTagsForTask { fn: import { getTagsForTask } from "@src/server/queries.ts", entities: [Task, Tag] } Any clues on that? @kapa.ai @kapa.ai can you suggest me with above problem?
type GetTagsForTaskPayload = { taskId: string }
export const getTagsForTask: GetTasks<GetTagsForTaskPayload, Tag[]> = async ({ taskId }, context) => { const task = await context.entities.Task.findUnique({ where: { id: taskId }, select: { tags: true }, })
return task?.tags || [] } Obiviously I have already include it in main.wasp: query getTagsForTask { fn: import { getTagsForTask } from "@src/server/queries.ts", entities: [Task, Tag] } Any clues on that? @kapa.ai @kapa.ai can you suggest me with above problem?
Let me check the knowledge base for you again. One moment! :books:
----------------------
I apologize, but I don't have enough context about the specific problem you're referring to. The knowledge sources provided don't contain any information about a previously mentioned problem. To provide an accurate and helpful answer, I would need more details about the issue you're facing with Wasp.
Could you please provide more information about the problem you're experiencing? This will allow me to search the knowledge sources for relevant information and give you a more targeted response.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @cubub, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?
If your tasks and tags have a many-to-many relationship, there must be a join entity which you'd need to include, but isn't shown here. Can you share the relevant entity definitions?
No, i use implicit many to many relation as prisma suggested since there is no extra information need to be stored. It is just a tag for task. I also dont see anywhere in wasp documentation state that we need to use explicit relation
And here is the model in schema.prisma:
model Task {
id String @id @default(cuid())
description String
isDone Boolean @default(false)
tags Tag[] @relation("TaskTags") // Many-to-many relation with Tag } model Tag { id String @id @default(cuid()) name String tasks Task[] @relation("TaskTags") // Many-to-many relation with Task }
tags Tag[] @relation("TaskTags") // Many-to-many relation with Tag } model Tag { id String @id @default(cuid()) name String tasks Task[] @relation("TaskTags") // Many-to-many relation with Task }
Apologies, I assumed you were using explicit relations as that was the approach of the OP.
Reading your query again, you’re using
select: { tags: true }
, but it should be include: { tags: true }
.
select
is for returning specific fields, not including entire relations, which it appears you want to do here.Prisma Client API | Prisma Documentation
API reference documentation for Prisma Client.
This message was 2 years old and since then we updated the docs 🙂 https://wasp.sh/docs/data-model/operations/queries#implementing-queries-in-node (green box)
Queries | Wasp
We'll explain what Queries are and how to use them. If you're looking for a detailed API specification, skip ahead to the API Reference.
You are right I would change this to a scary red color and make it vibrate though because I missed it.
I don't see a clear message stating that many to many must use these though so if it's your first time (as was mine) using wasp you might have a hard time understanding why your HTTP responses have the relation data in them but your react components don't!
I have changed as you suggested, but the error log is still the same, so I dont think that is the reason. Other 3 files that cause similar troubles also do not have the "include". Here is my repo: https://github.com/cubu/wasprelations/tree/main/src/api/v1/modules/tags
GitHub
wasprelations/src/api/v1/modules/tags at main · cubu/wasprelations
Contribute to cubu/wasprelations development by creating an account on GitHub.
Wohooo @cubub, you just became a Waspeteer level 3!
Thanks for sharing your repo, made it easier to debug. I've raised a PR, but for visibility, the root cause was that you were using the wrong operations in your functions, e.g.:
instead of:
This might've been a copy-and-paste issue, but reusing operations like this isn't valid.
While not an error, you were also importing unused entities, which I removed. You only need to declare an entity in
main.wasp
if you need to execute a db operation on it in your function. The entity isn't required if you're just returning another type through a relation.Wohooo @genyus, you just became a Waspeteer level 6!
Wow! it works perfectly. Thank you very much for your support @genyus .
Turn out I made the action markTaskAsDone and query getFilteredTask by using wrong operations (updateTask and getTasks). But it still works as normal so I think that is the direction to go.
I must careful next time.
No problem, you're welcome 👍🏾
Instead of openin a new thread I'll use this one since it already has valuble information on this topic
Does the Wasp type generation currently not automatically infer the fields of related models when you use explicit many-to-many relationships, only for implicit?
My schema is currently using explicit junction tables as per Prisma docs here:
https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations#querying-an-explicit-many-to-many
I'm asking because even when defining query as such
While the HTTP response is fine on a component when I want to access it in something such as
I will always get
Instead of openin a new thread I'll use this one since it already has valuble information on this topic
Does the Wasp type generation currently not automatically infer the fields of related models when you use explicit many-to-many relationships, only for implicit?
My schema is currently using explicit junction tables as per Prisma docs here:
https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations#querying-an-explicit-many-to-many
I'm asking because even when defining query as such
While the HTTP response is fine on a component when I want to access it in something such as
I will always get
Unless I manually define it using my junction table type such as
which makes the error go away 🙂
Wohooo @seppulcro, you just became a Waspeteer level 2!
Is this by design, a bug or have I missed something in the docs again? đź’€
@miho @kapa.ai
Let me check the knowledge base for you again. One moment! :books:
----------------------
I apologize, but I don't have enough context to determine what specific issue or behavior you're referring to. The knowledge sources provided don't contain any information about a particular problem or design decision that matches your question.
To provide an accurate and helpful answer, I would need more details about what you're experiencing with Wasp. Could you please provide more information about:
1. What specific behavior or feature you're observing?
2. What you expected to happen instead?
3. Any error messages or unexpected results you're seeing?
Once you provide more context, I'll be able to search the knowledge sources for relevant information and give you a more targeted response about whether it's by design, a bug, or something that might be explained in the documentation.
If you're referring to a specific part of the Wasp framework or a particular feature, please let me know, and I'll do my best to address your concern based on the available information.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @seppulcro, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?
@kapa.ai Does the Wasp type generation currently not automatically infer the fields of related models when you use explicit many-to-many relationships, only for implicit?
Process and Users have an explicitly declared relation in prisma.schema
Produces
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the information provided in the knowledge sources and your question, it appears that you're encountering an issue with type inference for explicit many-to-many relationships in Wasp. This behavior is likely not by design and might be a limitation or bug in the current implementation of Wasp's type generation system.
The problem you're experiencing is similar to an issue discussed in a Discord support thread. According to this thread, there's a known issue with full-stack type safety in Wasp, particularly when dealing with relations.
The core of the problem seems to be that the type annotation you're using for the query doesn't fully capture the structure of the data you're returning, especially for the related entities.
Here's what's happening:
1. You're using
GetAllUsers<void, (User & { processes: (ProcessesOnUsers & { process: Process })[] })[]>
as the type annotation for your query.
2. This type correctly includes the processes
field, but it doesn't explicitly include the assignedBy
and assignedAt
fields from the ProcessesOnUsers
model.
3. As a result, when you try to access process.assignedBy
in your React component, TypeScript doesn't recognize this property.
A community member from Wasp (Community Member 1) suggested a workaround for a similar issue:
"You need to annotate it more precisely since you are not returning only a list of Material
but also including the relations which change the type."
Applying this advice to your case, you might need to modify your type annotation to explicitly include all the fields you're selecting in your query. Something like this:
This issue has been noted for improvement in this GitHub issue. The Wasp team acknowledges that the current behavior is annoying and that a better solution would be to automatically infer the right type without requiring such complex manual type definitions.
In conclusion, this appears to be a limitation in the current version of Wasp rather than an intended design. The Wasp team is aware of this issue and is working on improving the type inference for these scenarios. For now, you'll need to use more explicit type annotations as a workaround.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @seppulcro, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?Unless I manually define it using my junction table type such as
which makes the error go away 🙂
Do implicit relations for prisma.schema also need relationship manually added? Or is there some way to infer when we generate them them when using
@kapa.ai
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the information provided in the knowledge sources and our previous conversation, it appears that the behavior you're experiencing is related to how Wasp handles type generation for relations, particularly for explicit many-to-many relationships.
To answer your questions:
1. Regarding implicit relations in Prisma schema:
The knowledge sources don't provide specific information about how Wasp handles implicit relations in Prisma schema. Therefore, I can't confidently say whether implicit relations would automatically include the relationship fields or if they would also require manual addition.
2. Automatically adding relationships when using imports from "wasp/entities":
Currently, there doesn't seem to be a way to automatically add the relationship fields when importing types from "wasp/entities". The issue you're experiencing is related to a known limitation in Wasp's type inference system.
As mentioned in our previous conversation, this behavior is not ideal and has been acknowledged by the Wasp team. They have noted this for improvement in this GitHub issue.
The current workaround, as you've discovered, is to manually specify the types using the junction table type (ProcessesOnUsers in your case). This approach correctly types the fields from your many-to-many relationship.
It's worth noting that the Wasp team is aware of these type inference issues and is working on improving them. As stated by a Wasp team member in a Discord thread:
"I know this is annoying! The better behaviour would be to automatically infer the right type and not make you define this complex type."
For now, the most reliable approach is to continue using explicit type annotations as you've done with
ProcessesOnUsers
. This ensures that TypeScript recognizes all the fields in your relations.
If you need further clarification or have more specific questions about Wasp's handling of Prisma relations and type generation, it might be helpful to reach out to the Wasp team directly through their Discord channel or by creating a GitHub issue.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @seppulcro, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?This is the correct type and implementation for your model.
Your original attempt fails because
user.processes
isn’t a collection of Process
objects as you’re expecting it to be, it’s a collection of ProcessesOnUsers
objects and the compiler rightly complains that assignedBy
doesn’t exist on the Process
type.
Remember that the assignedBy
column lives in your junction table, so that's where the property must be referenced from. If you needed to access the actual Process
objects, then you could do something like:
Yeah I figured as much! I But the question I has was if this was happening because I was using explicit relations, or is this the same case in implicit relations?
Also just out of pure tech curiosity, is this a limitation on wasp type generation or a general type inference generation issue?
Because from my limited understanding of typescript, if these were types defined exactly as the model is it is able to know hich property the nested object type has, right?
I understand that the fact that wasp is probably generating operation types based of the generated model, which can make this way trickier. This could also mean that maybe I'm not importing the types from the correct place?
Really enjoying using it so far, but I'm learning multiple new technologies at the same time and I might be confusing things
Thanks for the feedback!
Hey @seppulcro
have you tried typing your query like this:
(drop the second type param for
GetAllUsers
type)
This should allow TS to use the return type of getAllUsers
as the output of the querySame issue sadly
error TS2339: Property 'assignedBy' does not exist on type '{ id: number; name: string; description: string | null; createdAt: Date; updatedAt: Date; }'.only way it seems to work is via the approach described above and re-iterated by @genyus
Ah, so I think the problem now is that you’re explicitly typing your query results instead of allowing Typescript to infer them — and you’re hiding the relation properties as a result. Try this in combination with @miho’s suggestion above:
Yeah you're right! When going with @miho simplified approach and If I dont explicitly type the query results as you've suggested, wasp no longers throws the compiler error!
All that happens now is a tsc linter error
Parameter 'process' implicitly has an 'any' type.ts(7006)But the project compiles and runs fine 🙂 Thanks for the suggestions guys, is this the advised approach I should go for moving forward? Would also love some more insight on why this happens and how I could possibly avoid the linter error, or if It's better to just ignore it.
When you hover with your mouse over the
process
variables in your IDE, does it say any
or it gives you a type?Assuming you're using VS Code (or one of it's variants), I think you probably just need to reset the Typescript server so your IDE is aware of the latest type definitions. Open the Command Palette and select "Typescript: Reset TS Server"