从 v5 开始,Sequelize 提供了自己的 TypeScript 定义. 请注意,仅支持 TS >= 3.1.
由于 Sequelize 严重依赖于运行时属性分配,因此 TypeScript 在开箱即用时不会很有用. 为了使模型可用,需要大量的手动类型声明.
安装
为了避免非 TS 用户的安装膨胀,你必须手动安装以下键入程序包:
@types/node (这是通常是必须的)
@types/validator
@types/bluebird
使用
最小 TypeScript 项目的示例:
import { Sequelize, Model, DataTypes, BuildOptions } from 'sequelize'; import { HasManyGetAssociationsMixin, HasManyAddAssociationMixin, HasManyHasAssociationMixin, Association, HasManyCountAssociationsMixin, HasManyCreateAssociationMixin } from 'sequelize'; class User extends Model { public id!: number; // Note that the `null assertion` `!` is required in strict mode. public name!: string; public preferredName!: string | null; // for nullable fields // timestamps! public readonly createdAt!: Date; public readonly updatedAt!: Date; // Since TS cannot determine model association at compile time // we have to declare them here purely virtually // these will not exist until `Model.init` was called. public getProjects!: HasManyGetAssociationsMixin<Project>; // Note the null assertions! public addProject!: HasManyAddAssociationMixin<Project, number>; public hasProject!: HasManyHasAssociationMixin<Project, number>; public countProjects!: HasManyCountAssociationsMixin; public createProject!: HasManyCreateAssociationMixin<Project>; // You can also pre-declare possible inclusions, these will only be populated if you // actively include a relation. public readonly projects?: Project[]; // Note this is optional since it's only populated when explicitly requested in code public static associations: { projects: Association<User, Project>; }; } const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb'); class Project extends Model { public id!: number; public ownerId!: number; public name!: string; public readonly createdAt!: Date; public readonly updatedAt!: Date; } class Address extends Model { public userId!: number; public address!: string; public readonly createdAt!: Date; public readonly updatedAt!: Date; } Project.init({ id: { type: DataTypes.INTEGER.UNSIGNED, // you can omit the `new` but this is discouraged autoIncrement: true, primaryKey: true, }, ownerId: { type: DataTypes.INTEGER.UNSIGNED, allowNull: false, }, name: { type: new DataTypes.STRING(128), allowNull: false, }}, { sequelize, tableName: 'projects', }); User.init({ id: { type: DataTypes.INTEGER.UNSIGNED, autoIncrement: true, primaryKey: true, }, name: { type: new DataTypes.STRING(128), allowNull: false, }, preferredName: { type: new DataTypes.STRING(128), allowNull: true }}, { tableName: 'users', sequelize: sequelize, // this bit is important }); Address.init({ userId: { type: DataTypes.INTEGER.UNSIGNED, }, address: { type: new DataTypes.STRING(128), allowNull: false, }}, { tableName: 'address', sequelize: sequelize, // this bit is important }); // Here we associate which actually populates out pre-declared `association` static and other methods. User.hasMany(Project, { sourceKey: 'id', foreignKey: 'ownerId', as: 'projects' // this determines the name in `associations`! }); Address.belongsTo(User, {targetKey: 'id'}); User.hasOne(Address,{sourceKey: 'id'}); async function stuff() { // Please note that when using async/await you lose the `bluebird` promise context // and you fall back to native const newUser = await User.create({ name: 'Johnny', preferredName: 'John', }); console.log(newUser.id, newUser.name, newUser.preferredName); const project = await newUser.createProject({ name: 'first!', }); const ourUser = await User.findByPk(1, { include: [User.associations.projects], rejectOnEmpty: true, // Specifying true here removes `null` from the return type! }); console.log(ourUser.projects![0].name); // Note the `!` null assertion since TS can't know if we included // the model or not }
使用 sequelize.define
当我们使用 sequelize.define 方法定义模型时,TypeScript 不知道如何生成 class 定义. 因此,我们需要做一些手动工作,并声明一个接口和一个类型,并最终将 .define 的结果转换为 static 类型.
// 我们需要为模型声明一个接口,该接口基本上就是我们的类 interface MyModel extends Model { readonly id: number; } // 需要声明静态模型,以便 `findOne` 等使用正确的类型. type MyModelStatic = typeof Model & { new (values?: object, options?: BuildOptions): MyModel; } // TS 无法从 `.define` 调用中派生出正确的类定义,因此我们需要在此处进行强制转换. const MyDefineModel = <MyModelStatic>sequelize.define('MyDefineModel', { id: { primaryKey: true, type: DataTypes.INTEGER.UNSIGNED, } }); async function stuffTwo() { const myModel = await MyDefineModel.findByPk(1, { rejectOnEmpty: true, }); console.log(myModel.id); }