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

Next.js14/Next-auth5 Session类型未更新,TS提示user不存在

解决Next-auth中TypeScript提示“Property 'user' does not exist on type 'Session | null'”问题

问题根源

你遇到的问题主要来自两个方面:

  • Next-auth的TypeScript模块扩展未被正确合并
  • auth()函数可能返回null(未登录状态),直接解构user会触发类型检查错误

解决方案

1. 合并Next-auth的模块声明

将auth.ts中分开的两个declare module "next-auth"合并为一个,确保TypeScript能正确识别接口扩展:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { authConfig } from "./authconfig";
import { connectDb } from "./lib/utils";
import { User } from "./lib/models";
import bcrypt from "bcrypt";
import { UserType } from "./lib/types";

// 合并模块声明,确保接口扩展生效
declare module "next-auth" {
  interface Session {
    user?: UserType;
  }

  interface User {
    username: string;
    img: string;
  }
}

const login = async (credentials: Partial<Record<string, unknown>>) => {
  try {
    connectDb();
    const user = await User.findOne({ username: credentials.username });

    if (!user) throw new Error("Invalid credentials");

    const isPasswordCorrect = await bcrypt.compare(
      credentials.password as string,
      user.password
    );

    if (!isPasswordCorrect) throw new Error("Invalid credentials");

    return user;
  } catch (error) {
    console.log(error);
    throw new Error("Login failed");
  }
};

export const { signIn, signOut, auth } = NextAuth({
  ...authConfig,
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        try {
          const user = await login(credentials);
          return user;
        } catch (error) {
          return null;
        }
      },
    }),
  ],
  callbacks: {
    async session({ session, user }) {
      // 优化赋值逻辑,避免依赖原session.user存在
      session.user = {
        ...session.user,
        username: user.username,
        img: user.img,
      } as UserType;
      return session;
    },
  },
});

2. 处理auth()返回的null情况

在Sidebar组件中,auth()可能返回null(用户未登录时),需先判断session是否存在再获取user:

import { MdLogout } from "react-icons/md";
import styles from "./sidebar.module.scss";
import MenuLink from "./menuLink/menuLink";
import Image from "next/image";
import { MENU_ITEMS } from "@/app/data/menuItems";
import { auth, signOut } from "@/app/auth";

const Sidebar = async () => {
  const session = await auth();
  // 先确认session存在,再提取user
  const user = session?.user;
  
  return (
    <div className={styles.container}>
      <div className={styles.user}>
        <Image
          className={styles.userImage}
          priority
          src={user?.img || "/noavatar.png"}
          alt=""
          width="50"
          height="50"
        />
        <div className={styles.userDetail}>
          <span className={styles.username}>{user?.username}</span>
          <span className={styles.userTitle}>Administrator</span>
        </div>
      </div>
      <ul className={styles.list}>
        {MENU_ITEMS.map((category) => (
          <li key={category.title}>
            <span className={styles.category}>{category.title}</span>
            {category.list.map((item) => (
              <MenuLink item={item} key={item.title} />
            ))}
          </li>
        ))}
      </ul>
      <form
        action={async () => {
          "use server";
          await signOut();
        }}
      >
        <button className={styles.logout}>
          <MdLogout />
          Log out
        </button>
      </form>
    </div>
  );
};

export default Sidebar;

3. 额外检查:确保UserType类型匹配

确认你的UserType类型和扩展的User接口结构一致,例如:

// ./lib/types.ts
export type UserType = {
  id?: string;
  username: string;
  img: string;
  // 其他业务所需字段
};

关键说明

  • TypeScript要求同一模块的声明必须合并,分开写会导致扩展失效
  • auth()函数返回类型为Session | null,必须处理null情况才能安全访问user
  • 优化session回调逻辑,避免依赖默认session.user的存在,确保自定义字段正确赋值

内容的提问来源于stack exchange,提问作者CzechCoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:23:17