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

Sequelize+GraphQL中user.password与user.id类型错误解决问询

GraphQL + Sequelize登录功能的TypeScript类型错误解决

问题概述

在实现用户登录功能时遇到两个TypeScript错误:

  1. 访问user.password或user.id时触发错误:Property 'password' does not exist on type 'Model<any, any>'
  2. 修改User Model的TypeScript接口定义后,出现Cannot find name 'UserAttributes'错误

解决方案

1. 初始类型错误的根源

Sequelize默认生成的Model类型为Model<any, any>,TypeScript无法识别自定义的id、password等属性,必须给Model定义明确的类型接口以实现正确的类型推断。

2. 修正User Model的类型定义

修改Model时的错误是引用了未定义的UserAttributes接口,只需将未定义的接口名替换为已定义的类型,或直接将接口命名为UserAttributes即可。以下是正确的Model代码:

import { DataTypes, Model, Optional } from 'sequelize';
import sequelize from '../config/sequalize';

// 定义用户属性,createdAt和updatedAt为可选,因为Sequelize会自动生成
interface UserAttributes {
  id: number;
  email: string;
  password: string;
  createdAt?: Date;
  updatedAt?: Date;
}

// 定义实例类型:继承Model,同时指定创建实例时可省略id(自增主键)
interface UserInstance extends Model<UserAttributes, Optional<UserAttributes, 'id'>>, UserAttributes {}

const User = sequelize.define<UserInstance, UserAttributes>(
  'user',
  {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    timestamps: true,
  }
);

export default User;

3. 修正GraphQL Resolver中的类型与细节

修正后User.findOne会返回UserInstance | null,TypeScript可正确识别user.password和user.id。同时修正错误提示的描述,并确保JWT payload的类型匹配:

// ... 其他导入代码不变

// 修正JWT payload接口命名,提升可读性
interface JwtPayload {
  id: string;
}

const createRefreshToken = (payload: JwtPayload) => {
  return jwt.sign(payload, config.JWT_SECRET, {
    expiresIn: '7d',
  });
};

// ... UserType定义不变

const mutation = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    login: {
      type: UserType,
      args: {
        email: { type: GraphQLString },
        password: { type: GraphQLString },
      },
      async resolve(parent, args, res) {
        const user = await User.findOne({ where: { email: args.email } });
        if (!user) {
          throw new Error('User not found'); // 修正错误提示内容,原提示逻辑不符
        }
        const isMatch = await bcrypt.compare(args.password, user.password);
        if (!isMatch) {
          throw new Error('Invalid password');
        }
        // 将number类型的id转为string,匹配JwtPayload接口要求
        const refresh_token = createRefreshToken({ id: user.id.toString() });

        res.cookie('refreshtoken', refresh_token, {
          httpOnly: true,
          path: '/user/refresh_token',
          maxAge: 7 * 24 * 60 * 60 * 1000, // 7天有效期
        });

        return { msg: 'Login success!' };
      },
    },
  },
});

额外注意事项

  • 使用Optional<UserAttributes, 'id'>是因为创建用户时无需手动传入自增的id字段,Sequelize会自动生成。
  • 若使用Sequelize v6及以上版本,类型定义已内置,无需额外安装@types/sequelize。
  • 确保sequelize数据库连接配置正确,且依赖包已安装完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:02:52