从 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);
}