NextAuth.js TypeScript中authorize函数类型不兼容问题求助
问题场景
基于Next.js 13.5.4 + NextAuth.js ^4.23.2的TypeScript项目中,使用Credentials Provider时,api/auth/[...nextauth]/route.ts里的authorize函数出现类型错误。
相关代码
api/auth/[...nextauth]/route.ts片段:
CredentialsProvider({ name: 'credentials', credentials: {}, async authorize(credentials: any) { const {email, password} = credentials try { const user = await prisma.user.findFirst({ where: { email: email } }) if (!user) { return null } const passwordMatch = await bcrypt.compare(password, user.password) if (!passwordMatch) { return null } return user } catch (error) { console.error("ERROR AuthOptions: ", error); } }, }),
错误信息
Type '(credentials: any) => Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type '(credentials: Record<never, string>, req: Pick<RequestInternal, "body" | "query" | "headers" | "method">) => Awaitable<User>'. Type 'Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type 'Awaitable<User>'. Type 'Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type 'PromiseLike<User>'. Types of property 'then' are incompatible. Type '<TResult1 = { id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }, TResult2 = never>(onfulfilled?: (value: { id: number; firstName: string; ... 5 more ...; updatedAt: Date; }) => TResult1 | PromiseLike<...>, onrejected?: (reason: an...' is not assignable to type '<TResult1 = User, TResult2 = never>(onfulfilled?: (value: User) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<...>'. Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. Types of parameters 'value' and 'value' are incompatible. Type '{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }' is not assignable to type 'User'. Types of property 'id' are incompatible. Type 'number' is not assignable to type 'string'.
ts.config配置
{ "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": ["./*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] }
错误原因
NextAuth.js默认的User类型规定id为字符串类型,但你的Prisma用户模型中id是数字类型,同时返回的用户对象包含了password字段(该字段不属于默认User类型),导致类型不兼容。
解决方案
方案1:转换用户字段类型并过滤敏感信息
直接修改authorize函数的返回值,将id转为字符串,同时过滤掉password字段(避免暴露敏感数据+符合类型要求):
async authorize(credentials: { email?: string; password?: string }) { const { email, password } = credentials; if (!email || !password) return null; try { const user = await prisma.user.findFirst({ where: { email } }); if (!user) return null; const passwordMatch = await bcrypt.compare(password, user.password); if (!passwordMatch) return null; // 转换id为字符串,过滤password字段 return { id: user.id.toString(), firstName: user.firstName, lastName: user.lastName, email: user.email, telephone: user.telephone, createdAt: user.createdAt, updatedAt: user.updatedAt }; } catch (error) { console.error("ERROR AuthOptions: ", error); return null; // 确保异常时也返回null,符合Awaitable<User | null>类型 } }
同时给credentials定义明确的类型,替换原来的any,提升类型安全性。
方案2:自定义NextAuth的User类型(保留数字id)
如果不想转换id类型,可以扩展NextAuth的默认类型,让它适配你的用户模型:
- 在项目根目录创建
types/next-auth.d.ts文件:
import NextAuth from "next-auth"; declare module "next-auth" { interface User { id: number; firstName: string; lastName: string; email: string; telephone: string; createdAt: Date; updatedAt: Date; // 不要包含password字段,避免敏感数据暴露 } }
- 修改
tsconfig.json的include数组,确保包含自定义类型文件:
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "types/**/*.ts"],
- 回到
authorize函数,过滤掉password字段后返回用户:
return { id: user.id, firstName: user.firstName, lastName: user.lastName, email: user.email, telephone: user.telephone, createdAt: user.createdAt, updatedAt: user.updatedAt };
额外注意点
- 永远不要把用户的
password字段返回给前端,既不符合NextAuth的类型要求,也存在严重的安全风险。 - 确保
authorize函数的返回值始终符合Awaitable<User | null>类型,异常场景下也要返回null,避免类型错误。
内容的提问来源于stack exchange,提问作者Tharisha Perera
相关产品推荐
相关产品推荐

