Since v5, Sequelize provides its own TypeScript definitions. Please note that only TS >= 3.1 is supported.
As Sequelize heavily relies on runtime property assignments, TypeScript won't be very useful out of the box. A decent amount of manual type declarations are needed to make models workable.
In order to avoid installation bloat for non TS users, you must install the following typing packages manually:
@types/node
(this is universally required)@types/validator
@types/bluebird
Example of a minimal TypeScript project:
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
TypeScript doesn't know how to generate a class
definition when we use the sequelize.define
method to define a Model. Therefore, we need to do some manual work and declare an interface and a type, and eventually cast the result of .define
to the static type.
// We need to declare an interface for our model that is basically what our class would be interface MyModel extends Model { readonly id: number; } // Need to declare the static model so `findOne` etc. use correct types. type MyModelStatic = typeof Model & { new (values?: object, options?: BuildOptions): MyModel; } // TS can't derive a proper class definition from a `.define` call, therefor we need to cast here. const MyDefineModel = <MyModelStatic>sequelize.define('MyDefineModel', { id: { primaryKey: true, type: DataTypes.INTEGER.UNSIGNED, } }); function stuffTwo() { MyDefineModel.findByPk(1, { rejectOnEmpty: true, }) .then(myModel => { console.log(myModel.id); }); }
Copyright © 2014–present Sequelize contributors
Licensed under the MIT License.
https://sequelize.org/master/manual/typescript.html