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

如何在Sequelize-Typescript中创建关联用户的RefreshToken?

解决Sequelize-Typescript关联创建RefreshToken的类型错误

我花费数周时间尝试在Sequelize-Typescript中实现关联创建操作,需求是通过用户ID查找用户后,创建与该用户关联的RefreshToken。实现代码如下:

public createToken = async (userId: number, t: string) => {
    const later = new Date();
    const forUser = await User.findOne({ where: { userId: userId } });
    if (!forUser) throw new Error("No user found for this id");
    const rtedUser = RefreshToken.create(
        {
            token: t,
            isActive: true,
            expires: later,
            users: [forUser],
        },
        { include: [User] },
    );

    return rtedUser;
};

运行时报错:

src/db/dao/refreshToken.dao.ts:21:17 - error TS2345: Argument of type '{ token: string; isActive: true; expires: Date; users: User[]; }' is not assignable to parameter of type 'Optional<RefreshTokenCreationAttributes, "tokenId">'.
  Object literal may only specify known properties, and 'users' does not exist in type 'Optional<RefreshTokenCreationAttributes, "tokenId">'.

21                 users: [forUser],
                   ~~~~~~~~~~~~~~~~

模型定义

User.ts

import { Optional } from "sequelize";
import { Table, Column, Model, HasMany, CreatedAt, UpdatedAt, PrimaryKey } from "sequelize-typescript";
import { RefreshToken } from "./RefreshToken.model";

interface UserAttributes {
    userId: number;
    email: string;
    firstName: string;
}

interface UserCreationAttributes extends Optional<UserAttributes, "userId"> {}

@Table
export class User extends Model<UserAttributes, UserCreationAttributes> {
    @PrimaryKey
    @Column
    userId!: number;

    @Column
    email!: string;

    @Column
    firstName!: string;

    @HasMany(() => RefreshToken, "tokenId")
    rts?: RefreshToken[];

    @CreatedAt
    @Column
    creationDate!: Date;

    @UpdatedAt
    @Column
    updatedOn!: Date;
}

RefreshToken.ts

import { Sequelize as S, Optional } from "sequelize";
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, PrimaryKey, Table, UpdatedAt } from "sequelize-typescript";
import { User } from "./User.model";

interface RefreshTokenAttributes {
    tokenId: number;
    token: string;
    isActive: boolean;
    expires: Date;
}

interface RefreshTokenCreationAttributes extends Optional<RefreshTokenAttributes, "tokenId"> {}

@Table
export class RefreshToken extends Model<RefreshTokenAttributes, RefreshTokenCreationAttributes> {
    @PrimaryKey
    @Column
    tokenId!: number;

    @Column
    token!: string;

    @Column
    isActive!: boolean;

    @Column
    expires!: Date;

    @BelongsTo(() => User)
    user!: User;

    @ForeignKey(() => User)
    @Column
    userId!: number;

    @CreatedAt
    @Column
    creationDate!: Date;

    @UpdatedAt
    @Column
    updatedOn!: Date;
}

解决方案

1. 修正模型定义

  • 补充RefreshToken属性接口的外键定义:模型中已实现userId外键字段,但RefreshTokenAttributes接口未包含该字段,导致TS类型校验失败,补充后接口如下:
interface RefreshTokenAttributes {
    tokenId: number;
    token: string;
    isActive: boolean;
    expires: Date;
    userId: number; // 新增外键字段定义
}

interface RefreshTokenCreationAttributes extends Optional<RefreshTokenAttributes, "tokenId"> {}
  • 修正User模型的关联外键:原@HasMany装饰器中外键参数错误,RefreshToken关联User的外键是userId而非tokenId,修正后代码:
@HasMany(() => RefreshToken, "userId") // 将"tokenId"改为"userId"
rts?: RefreshToken[];

2. 调整RefreshToken创建逻辑

无需在create参数中传入users数组(该属性不属于RefreshToken的创建类型),直接通过外键userId关联用户即可:

public createToken = async (userId: number, t: string) => {
    const later = new Date();
    const forUser = await User.findOne({ where: { userId: userId } });
    if (!forUser) throw new Error("No user found for this id");
    
    const rtedToken = await RefreshToken.create({
        token: t,
        isActive: true,
        expires: later,
        userId: forUser.userId // 使用用户ID关联
    });

    return rtedToken;
};

可选:通过用户实例关联方法创建(更符合Sequelize设计)

模型关联修正后,可通过用户实例自动生成的关联方法创建RefreshToken:

public createToken = async (userId: number, t: string) => {
    const later = new Date();
    const forUser = await User.findOne({ where: { userId: userId } });
    if (!forUser) throw new Error("No user found for this id");
    
    // 调用用户实例的createRt方法(关联名rts的单数形式)
    const rtedToken = await forUser.createRt({
        token: t,
        isActive: true,
        expires: later
    });

    return rtedToken;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:05:25