You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:40:44