使用NextAuth Credentials与TypeScript时遭遇类型错误求助
解决NextAuth Credentials授权函数的TypeScript类型错误
问题背景
在TypeScript项目中使用NextAuth的Credentials提供者时,照搬官方示例代码出现类型错误,核心问题是authorize函数返回的Prisma User类型与NextAuth的User类型不兼容。
错误信息
Type '(credentials: Record<"email" | "password", string> | undefined, res: Pick<RequestInternal, "query" | "body" | "headers" | "method">) => Promise<...>' is not assignable to type '(credentials: Record<"email" | "password", string> | undefined, req: Pick<RequestInternal, "query" | "body" | "headers" | "method">) => Awaitable<...>'. Type 'Promise<User | null>' is not assignable to type 'Awaitable<User | null>'. Type 'Promise<User | null>' is not assignable to type 'PromiseLike<User | null>'. Types of property 'then' are incompatible. Type '<TResult1 = User | null, TResult2 = never>(onfulfilled?: ((value: User | null) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => Promise<...>' is not assignable to type '<TResult1 = User | null, TResult2 = never>(onfulfilled?: ((value: User | null) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => PromiseLike<...>'. Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. Types of parameters 'value' and 'value' are incompatible. Type 'import("/app/node_modules/.prisma/client/index").User | null' is not assignable to type 'import("/app/node_modules/next-auth/core/types").User | null'. Type 'import("/app/node_modules/.prisma/client/index").User' is not assignable to type 'import("/app/node_modules/next-auth/core/types").User'. Types of property 'id' are incompatible. Type 'number' is not assignable to type 'string'.ts(2322) credentials.d.ts(13, 5): The expected type comes from property 'authorize' which is declared here on type 'UserCredentialsConfig<{ email: { label: string; type: string; }; password: { label: string; type: string; }; }>'
现有代码
/pages/auth/[...nextauth].ts
return await NextAuth(req, res, { providers: [ CredentialsProvider({ name: 'Credentials', credentials: { email: { label: 'Email', type: 'email' }, password: { label: 'Password', type: 'password' }, }, async authorize(credentials, req) { const { email, password } = credentials as { email: string; password: string; }; const { user } = await loginUser({ email, password }); if (!user) { return null; } return user; }, }), ], callbacks: { session({ session, token, user }) { return session; }, async jwt({ token }) { return token; }, }, adapter: PrismaAdapter(prisma), });
types/next-auth.d.ts
import 'next-auth'; import { User as UserModel } from '@prisma/client'; declare module 'next-auth' { interface User extends UserModel {} interface Session { user: User; expires: string; } }
loginUser函数
import { compare } from 'bcryptjs'; import prisma from '@/libs/prisma'; import { User } from '@prisma/client'; import { UserLoginData } from '@/types/auth'; export const LoginUser = async ({ email, password, }: UserLoginData): Promise<{ user: User | null; error: Error | null; }> => { const user = await prisma.user.findUnique({ where: { email } }); if (!user) { return { user: null, error: new Error(`User with email: ${email} does not exist.`), }; } const isValid = password && user.password && (await compare(password, user.password)); if (!isValid) { return { user, error: new Error('Invalid password.'), }; } return { user, error: null }; };
解决方案
方案1:修改NextAuth类型定义,兼容Number类型的ID
NextAuth核心类型中的User接口默认id为string类型,而你的Prisma User模型中id是number类型。修改types/next-auth.d.ts,明确覆盖id的类型:
import 'next-auth'; import { User as UserModel } from '@prisma/client'; declare module 'next-auth' { // 扩展User接口,明确id为number类型,覆盖NextAuth默认的string interface User extends UserModel { id: number; } interface Session { user: User; expires: string; } }
方案2:在授权函数中转换ID类型
在authorize函数中,将Prisma返回的User的id转换为string,匹配NextAuth的默认类型要求:
async authorize(credentials, req) { const { email, password } = credentials as { email: string; password: string; }; const { user } = await loginUser({ email, password }); if (!user) { return null; } // 将number类型的id转换为string,返回符合NextAuth类型要求的对象 return { ...user, id: user.id.toString() }; }
原因说明
错误根源是类型不兼容:NextAuth默认User接口的id为string,而你的Prisma User模型中id是number。即使通过extends继承Prisma的User类型,TypeScript会因为基础接口的id类型冲突而报错,必须显式处理这个类型差异。
内容的提问来源于stack exchange,提问作者Hai Nguyen
相关产品推荐
相关产品推荐

