W
Wasp•6d ago
mario.p

"Property 'value' does not exist on type XYZ"- but it exists. What am I doing wrong?

Hi everyone! In advance I would say that I am new to this technology and I am stuck with something that looks like a bug in WASP but I am not sure. The error I receive when the build fails: Property 'user' does not exist on type '{ id: number; userId: string; } The code: File mypage.tsx
import { type CourseChapter, type Course, UserInstructor, User } from 'wasp/entities';

// ... other code

function CourseForm({ courseId }: { courseId: string }) {

const { data: instructors } = useQuery(getUserInstructors)

// other code...
<select>
{instructors?.map((instructor: UserInstructor) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user.username}
</option>
))}
</select>
// ...
import { type CourseChapter, type Course, UserInstructor, User } from 'wasp/entities';

// ... other code

function CourseForm({ courseId }: { courseId: string }) {

const { data: instructors } = useQuery(getUserInstructors)

// other code...
<select>
{instructors?.map((instructor: UserInstructor) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user.username}
</option>
))}
</select>
// ...
This is my operations file File operations.ts
import { Course, CourseCategory, CourseChapter, UserInstructor } from 'wasp/entities'
import { type GetCourseCategories, type GetUserInstructors, type GetCourses, type GetCourseChapters } from 'wasp/server/operations'

// ... other code

export const getUserInstructors: GetUserInstructors<void, UserInstructor[]> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
import { Course, CourseCategory, CourseChapter, UserInstructor } from 'wasp/entities'
import { type GetCourseCategories, type GetUserInstructors, type GetCourses, type GetCourseChapters } from 'wasp/server/operations'

// ... other code

export const getUserInstructors: GetUserInstructors<void, UserInstructor[]> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
File Schema.prisma
// ...
model UserInstructor {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId String @unique
courses Course[]
}
// ...
model UserInstructor {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId String @unique
courses Course[]
}
What I have already tried that didn't work: - wasp clean - Adding new fields to the UserInstructor model and running wasp db dev-migrate I am working on Ubuntu 22 with Wasp 0.16.2 I hope someone can help me 🙂 Thanks!
3 Replies
kapa.ai
kapa.ai•6d ago
Hi @mario.p. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the information provided in your question and the knowledge sources available, it appears you're encountering a TypeScript error related to the user property on the UserInstructor type. This is likely due to a mismatch between the TypeScript types generated by Wasp and the actual data structure you're working with. Here are a few potential solutions and things to check: 1. Ensure your Wasp version is up to date. You mentioned using Wasp 0.16.2, which is relatively recent, but it's always good to check if there's a newer version available. 2. The error suggests that the UserInstructor type only includes id and userId properties. This could be due to the TypeScript definitions not being properly updated after changes to your schema. Try running wasp db migrate-dev again to ensure all changes are reflected in the generated types. 3. If the above doesn't work, you might need to manually update the TypeScript types. You can do this by adding a type assertion in your component:
{instructors?.map((instructor: UserInstructor & { user: { username: string } }) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user.username}
</option>
))}

{instructors?.map((instructor: UserInstructor & { user: { username: string } }) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user.username}
</option>
))}

This tells TypeScript that user exists on UserInstructor and has a username property. 4. Another approach is to check if the user property exists before accessing it:
{instructors?.map((instructor: UserInstructor) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user?.username}
</option>
))}

{instructors?.map((instructor: UserInstructor) => (
<option key={instructor.id} value={String(instructor.id)}>
{instructor.user?.username}
</option>
))}

5. If none of the above work, there might be an issue with how the types are being generated or imported. You could try explicitly importing the UserInstructor type from the generated types file (usually located in the .wasp directory) instead of from wasp/entities. If these solutions don't resolve the issue, it's possible there's a bug in Wasp's type generation. In that case, you might want to report this as an issue on the Wasp GitHub repository. Remember to always run wasp db migrate-dev after making changes to your schema, and wasp start to ensure all types are regenerated correctly. Discord Support Thread: Object relation doesn't compile to TypeScript suggests that there might be differences in how types are generated between Wasp versions. If you've recently upgraded from an older version, you might need to adjust how you're importing and using the types. If the problem persists, consider reaching out to the Wasp community on Discord for more specific help, as they might be able to provide more tailored assistance based on your exact setup and version. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @mario.p, 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?
Vinny (@Wasp)
Vinny (@Wasp)•5d ago
It looks like the Bot gave you the half of the right answer. What you need to do is modify your return type on your getUserInstructors operation so that it returns a (UserInstructor & { user: { username: string } } type @kapa.ai can you show us how to improve the following function so that the return type includes both objects being returned by the function:
export const getUserInstructors: GetUserInstructors<void, UserInstructor[]> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
export const getUserInstructors: GetUserInstructors<void, UserInstructor[]> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
kapa.ai
kapa.ai•5d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You're absolutely right, and thank you for providing that clarification. I apologize for not addressing this specific aspect in my previous answer. Let's improve the getUserInstructors function to correctly type the return value, including both the UserInstructor and the nested user object. Here's how you can modify the function to include the correct return type:
import { UserInstructor, User } from 'wasp/entities'
import { GetUserInstructors } from 'wasp/server/operations'

export const getUserInstructors: GetUserInstructors<
void,
(UserInstructor & { user: Pick<User, 'id' | 'username'> })[]
> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
import { UserInstructor, User } from 'wasp/entities'
import { GetUserInstructors } from 'wasp/server/operations'

export const getUserInstructors: GetUserInstructors<
void,
(UserInstructor & { user: Pick<User, 'id' | 'username'> })[]
> = async (args, context) => {
return context.entities.UserInstructor.findMany({
orderBy: { id: 'asc' },
include: {
user: {
select: {
id: true,
username: true
}
}
},
})
}
In this improved version: 1. We've modified the return type of GetUserInstructors to include both the UserInstructor and the nested user object with its selected fields. 2. We use Pick<User, 'id' | 'username'> to specify that we're only including the id and username fields from the User entity, which matches the select statement in the query. 3. The [] at the end indicates that it's an array of these combined types. This approach ensures that TypeScript understands the exact structure of the objects being returned by the function, including the nested user object with its id and username properties. By specifying the return type this way, you should resolve the TypeScript error you were encountering in your component when trying to access instructor.user.username. Discord support thread: Object relation doesn't compile to TypeScript mentions a similar issue and solution, confirming that this approach of explicitly typing the return value with included relations is the correct way to handle such cases in Wasp. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Vinny (@Wasp), 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?

Did you find this page helpful?