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

Nextjs Server Actions、Prisma、NextAuth中的TypeScript类型错误求助

解决NextAuth+Prisma关联用户笔记时的TypeScript类型错误

我用Next.js开发笔记应用,采用Vercel Postgres做数据库、Prisma当ORM、NextAuth实现用户认证。集成Prisma和NextAuth后,尝试创建归属当前用户的笔记时触发TypeScript错误:

Type 'string | null | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'.

错误出在email: session?.user?.email这一行——NextAuth返回的session中user.email可能为null或undefined,但Prisma要求关联用户的email必须是字符串类型。以下是两种更合理的解决方式:

原问题代码

import { options } from "../../api/auth/[...nextauth]/options";
import { getServerSession } from "next-auth/next";
import db from "../../api/db";

export default async function Page() {
  const session = await getServerSession(options);
  if (!session) return;

  async function addNote() {
    "use server";
    const res = await db.notes.create({
      data: {
        content: "Apple",
        category: "Fruit",
        owner: {
          connect: {
            email: session?.user?.email,
          },
        },
      },
    });
    return res;
  }

  const result = await addNote();
  console.log(result);
  return <>></>;
}

方案一:从认证流程强制返回必填邮箱

从根源消除类型不确定性,修改NextAuth配置和类型定义,确保session.user.email一定是字符串:

  1. 扩展NextAuth全局类型
    在项目根目录创建types/next-auth.d.ts,覆盖默认类型:
import NextAuth from "next-auth";

declare module "next-auth" {
  interface User {
    email: string; // 强制邮箱为必填字符串
  }

  interface Session {
    user: User;
  }
}
  1. 修改NextAuth回调逻辑
    在[...nextauth]/options.ts中,确保认证流程中只有带邮箱的用户能完成登录,同时同步JWT和Session的邮箱字段:
import type { NextAuthOptions } from "next-auth";
// 替换为你实际使用的认证提供商
import CredentialsProvider from "next-auth/providers/credentials";

export const options: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      // 你的认证逻辑配置
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        // 模拟用户查询逻辑,实际从数据库获取
        const user = { id: "1", email: credentials?.email };
        if (!user.email) throw new Error("用户必须提供邮箱");
        return user;
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) token.email = user.email;
      return token;
    },
    async session({ session, token }) {
      session.user.email = token.email as string;
      return session;
    },
  },
};

修改后TypeScript会自动推断session.user.email为字符串,无需额外校验。


方案二:业务层强校验+明确错误提示

如果不想修改全局类型,可在创建笔记的业务逻辑中做强校验,既解决类型问题,也保证业务合理性(无邮箱的用户不能创建笔记):

import { options } from "../../api/auth/[...nextauth]/options";
import { getServerSession } from "next-auth/next";
import db from "../../api/db";

export default async function Page() {
  const session = await getServerSession(options);
  if (!session) return;

  async function addNote() {
    "use server";
    // 强校验:无邮箱则抛出业务错误
    const userEmail = session.user.email;
    if (!userEmail) {
      throw new Error("无法创建笔记:当前用户未绑定邮箱");
    }

    const res = await db.notes.create({
      data: {
        content: "Apple",
        category: "Fruit",
        owner: {
          connect: {
            email: userEmail, // TS自动推断为字符串
          },
        },
      },
    });
    return res;
  }

  try {
    const result = await addNote();
    console.log(result);
  } catch (err) {
    console.error(err);
  }
  return <>></>;
}

方案合理性说明

  • 方案一从认证入口把关,确保只有符合业务要求(带邮箱)的用户能进入系统,从根源消除了email为空的可能,符合笔记归属用户的核心逻辑。
  • 方案二在业务操作前做校验,既解决TypeScript类型问题,也避免了无效的数据库操作,同时给出明确的错误信息,便于调试和后续给用户提示。

内容的提问来源于stack exchange,提问作者ajv-2005

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:16:13