Prisma Session模型无法关联User的TypeScript错误求助
解决Next.js中Prisma关联Session与User的两个问题:数据关联缺失和TypeScript类型错误
一、Session无法获取关联User数据的解决方案
Prisma默认不会自动加载关联模型的数据,必须在查询时显式指定要包含的关联:
- 在查询Session的代码中,添加
include: { user: true }来加载关联的User数据:
// 示例:查询Session并关联User const session = await prisma.session.findUnique({ where: { sessionToken: "YOUR_SESSION_TOKEN" }, include: { user: true } // 关键:指定加载关联的User });
- 修改
schema.prisma后,必须重新生成Prisma客户端,执行命令:
npx prisma generate
二、TypeScript错误“Property 'user' does not exist on type 'UserMenuButtonProps'”的解决方案
这个错误有两个原因:组件参数传递错误,以及Session类型未包含关联的User字段。
1. 修正组件参数传递方式
组件接收的是props对象,不是直接的session参数,需要解构props:
// 原错误写法 // export default function UserMenuButton(session: UserMenuButtonProps) { // 正确写法:解构props export default function UserMenuButton({ session }: UserMenuButtonProps) { const user = session?.user; // ... 其余代码保持不变 }
2. 扩展Session类型以包含User关联
@prisma/client提供的默认Session类型不包含关联的user字段,需要扩展类型:
import { Session, User } from "@prisma/client"; // 定义包含User关联的Session类型 type SessionWithUser = Session & { user: User; }; // 更新组件props的类型定义 interface UserMenuButtonProps { session: SessionWithUser | null; }
或者使用Prisma内置的类型生成工具更严谨:
import { Prisma } from "@prisma/client"; // 生成包含User关联的Session类型 const SessionWithUserArgs = Prisma.validator<Prisma.SessionArgs>()({ include: { user: true }, }); type SessionWithUser = Prisma.SessionGetPayload<typeof SessionWithUserArgs>; // 更新props类型 interface UserMenuButtonProps { session: SessionWithUser | null; }
修改后的完整组件代码
import { Session, User } from "@prisma/client" import Image from "next/image"; import profilepicplaceholder from "../../assets/profile-pic-placeholder.png" import { signIn, signOut } from "next-auth/react"; // 扩展Session类型,包含关联的User type SessionWithUser = Session & { user: User; }; interface UserMenuButtonProps { session : SessionWithUser | null } // 解构props参数 export default function UserMenuButton({ session }: UserMenuButtonProps) { const user = session?.user return( <div className="dropdown dropdown-end"> <label tabIndex={0} className="btn btn-ghost btn-circle"> { user? <Image src={user?.image || profilepicplaceholder } alt="profile pic" width={40} height={40} className="w-10 rounded-full"/>: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="inline-block h-5 w-5 stroke-current" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z" /> </svg> } </label> <ul tabIndex={0} className="dropdown-content menu rounded-box menu-sm z-3 mt-3 w-52 bg-base-100 p-2 shadow"> <li>{user? <button onClick={()=> signOut({callbackUrl:"/"})}>Sign out</button> : <button onClick={()=> signIn()}>Sign In</button>}</li> </ul> </div> ) }
内容的提问来源于stack exchange,提问作者siddhant daryanani
相关产品推荐
相关产品推荐

