如何在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
相关产品推荐
相关产品推荐

