node.js - การสร้างเมธอดของอินสแตนซ์ในโมเดล Sequelize โดยใช้ Typescript
ฉันต้องการขยายคลาส Sequelize Model เพื่อเพิ่มเมทอดของอินสแตนซ์อื่น ๆ แต่ TypeScript ยังคงแจ้งข้อผิดพลาดว่า "Property 'prototype' does not exist on type 'Model'"
const MyModel = (sequelize: Sequelize.Sequelize, dataTypes: Sequelize.DataTypes) => {
const User = sequelize.define<Instance, Attribute>(
"users",
{
id: {
type: dataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
email: {
type: dataTypes.STRING
},
...
},
{
tableName: "users",
...
},
);
User.prototype.verifyUser = function(password: string) {
...
};
return User;
};
ฉันคาดว่า User.prototype.verifyUser จะทำงานได้ แต่ TypeScript โวยวาย วิธีเพิ่มไปยัง typings ทำอย่างไร?
คำตอบ #1
ตามความคิดเห็นของ @Shadrech ฉันมีทางเลือกอีกทางหนึ่ง (น้อยกว่าการแก้ไขแบบแฮ็กและนามธรรม)
export interface UserAttributes {
...
}
export interface UserInstance extends Sequelize.Instance<UserAttributes>, UserAttributes {
}
interface UserModelInstanceMethods extends Sequelize.Model<UserInstance, UserAttributes> {
// Came to this question looking for a better approach to this
// You'll need root's definitions for invocation and prototype's for creation
verifyPassword: (password: string) => Promise<boolean>;
prototype: {
verifyPassword: (password: string) => Promise<boolean>;
};
}
const MyModel = (sequelize: Sequelize.Sequelize, dataTypes: Sequelize.DataTypes): UserModelInstanceMethods => {
const User = sequelize.define<UserInstance, UserAttributes>(
...
) as UserModelInstanceMethods;
User.prototype.verifyUser = function(password: string) {
...
};
return User;
}
การใช้โมเดลของคุณ:
sequelize.query("SELECT ...").then((user: UserInstance & UserModelInstanceMethods) => {
user.verifyPassword(req.body.password) // <= from UserModelInstanceMethods
user.getDataValue('name') // <= from UserInstance
})
คำตอบ #2
ตาม เอกสารหลักของ Sequelize TypeScript ฉันคิดว่าวิธีที่ดีที่สุดในการใช้งานคือการใช้ DataTypes.VIRTUAL และข้ามคุณสมบัติดังกล่าวด้วย ยูทิลิตี้ Omit ของ TypeScript ในอินเทอร์เฟซการสร้างโมเดล
สำคัญ! จำหมายเลขปัญหา#11675 ให้ได้!
- https://stackoverflow.com/a/69289067/717267
- https://github.com/sequelize/sequelize/issues/11675
ตัวอย่างง่ายๆ:
import {
Sequelize,
Model,
ModelDefined,
DataTypes,
Optional,
// ...
} from 'sequelize';
interface ProjectAttributes {
id: number;
ownerId: number;
name: string;
readonly createdAt: Date;
readonly updatedAt: Date;
// #region Methods
myMethod(name: string): Promise<void>; // <<<===
// #endregion
}
interface ProjectCreationAttributes extends Omit< // <<<===
Optional<
ProjectAttributes,
| 'id'
| 'createdAt'
>,
'myMethod' // <<<===
> {}
class Project extends Model<ProjectAttributes, ProjectCreationAttributes>
implements ProjectAttributes {
public id: ProjectAttributes['id'];
public ownerId: ProjectAttributes['ownerId'];
public name: ProjectAttributes['name'];
public readonly createdAt: ProjectAttributes['createdAt'];
public readonly updatedAt: ProjectAttributes['updatedAt'];
public readonly myMethod: ProjectAttributes['myMethod'] // <<<===
/**
* Initialization to fix Sequelize Issue #11675.
*
* @see https://stackoverflow.com/questions/66515762/configuring-babel-typescript-for-sequelize-orm-causes-undefined-properties
* @see https://github.com/sequelize/sequelize/issues/11675
* @ref #SEQUELIZE-11675
*/
constructor(values?: TCreationAttributes, options?: BuildOptions) {
super(values, options);
// All fields should be here!
this.id = this.getDataValue('id');
this.ownerId = this.getDataValue('ownerId');
this.name = this.getDataValue('name');
this.createdAt = this.getDataValue('createdAt');
this.updatedAt = this.getDataValue('updatedAt');
this.myMethod = async (name) => { // <<<===
// Implementation example!
await this.update({
name,
});
};
}
// #region Methods
public toString() {
return `@${this.name} [${this.ownerId}] #${this.id}`;
}
// #endregion
}
Project.init(
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
ownerId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
},
name: {
type: new DataTypes.STRING(128),
allowNull: false,
},
myMethod: { // <<<===
type: DataTypes.VIRTUAL(DataTypes.ABSTRACT),
}
},
{
sequelize,
tableName: "projects",
}
);
