Skip to main content

TypeScript

从 v5 开始,Sequelize 提供了自己的 TypeScript 定义. 请注意,仅支持 TS >= 3.1.

由于 Sequelize 严重依赖于运行时属性分配,因此 TypeScript 在开箱即用时不会很有用. 为了使模型可用,需要大量的手动类型声明.

安装#

为了避免非 TS 用户的安装膨胀,你必须手动安装以下键入程序包:

  • @types/node (在 node 项目中这是通常是必须的)
  • @types/validator

使用#

带有严格类型检查的最小 TypeScript 项目示例.

注意: 保持下代码与 /types/test/typescriptDocs/ModelInit.ts 保持同步,以确保其类型检查正确.

import {  Sequelize,  Model,  ModelDefined,  DataTypes,  HasManyGetAssociationsMixin,  HasManyAddAssociationMixin,  HasManyHasAssociationMixin,  Association,  HasManyCountAssociationsMixin,  HasManyCreateAssociationMixin,  Optional,} from 'sequelize';
const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
// These are all the attributes in the User modelinterface UserAttributes {  id: number;  name: string;  preferredName: string | null;}
// Some attributes are optional in `User.build` and `User.create` callsinterface UserCreationAttributes extends Optional<UserAttributes, 'id'> {}
class User extends Model<UserAttributes, UserCreationAttributes>  implements UserAttributes {  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>;  };}
interface ProjectAttributes {  id: number;  ownerId: number;  name: string;}
interface ProjectCreationAttributes extends Optional<ProjectAttributes, 'id'> {}
class Project extends Model<ProjectAttributes, ProjectCreationAttributes>  implements ProjectAttributes {  public id!: number;  public ownerId!: number;  public name!: string;
  public readonly createdAt!: Date;  public readonly updatedAt!: Date;}
interface AddressAttributes {  userId: number;  address: string;}
// You can write `extends Model<AddressAttributes, AddressAttributes>` instead,// but that will do the exact same thing as belowclass Address extends Model<AddressAttributes> implements AddressAttributes {  public userId!: number;  public address!: string;
  public readonly createdAt!: Date;  public readonly updatedAt!: Date;}
// 你还可以通过功能性方式定义模块interface NoteAttributes {  id: number;  title: string;  content: string;}
// 你还可以一次将多个属性设置为可选, 接口 NoteCreationAttributes 扩展了 Optional<NoteAttributes, 'id' | 'title'> {};
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,    },  },  {    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, // passing the `sequelize` instance is required  },);
Address.init(  {    userId: {      type: DataTypes.INTEGER.UNSIGNED,    },    address: {      type: new DataTypes.STRING(128),      allowNull: false,    },  },  {    tableName: 'address',    sequelize, // passing the `sequelize` instance is required  });
// And with a functional approach defining a module looks like thisconst Note: ModelDefined<  NoteAttributes,  NoteCreationAttributes> = sequelize.define(  'Note',  {    id: {      type: DataTypes.INTEGER.UNSIGNED,      autoIncrement: true,      primaryKey: true,    },    title: {      type: new DataTypes.STRING(64),      defaultValue: 'Unnamed Note',    },    content: {      type: new DataTypes.STRING(4096),      allowNull: false,    },  },  {    tableName: 'notes',  });
// 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 doStuffWithUser() {  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!  });
  // Note the `!` null assertion since TS can't know if we included  // the model or not  console.log(ourUser.projects![0].name);}

使用非严格类型#

Sequelize v5 的类型允许你定义模型而无需指定属性类型. 对于向后兼容以及在你觉得对属性进行严格检查是不值得的情况下, 这仍然是可行的.

注意: 使以下代码与 typescriptDocs/ModelInitNoAttributes.ts 保持同步,以确保其类型检查正确。

import { Sequelize, Model, DataTypes } from 'sequelize';
const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
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}
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, // passing the `sequelize` instance is required  },);
async function doStuffWithUserModel() {  const newUser = await User.create({    name: 'Johnny',    preferredName: 'John',  });  console.log(newUser.id, newUser.name, newUser.preferredName);
  const foundUser = await User.findOne({ where: { name: 'Johnny' } });  if (foundUser === null) return;  console.log(foundUser.name);}

使用 sequelize.define#

在 v5 之前的 Sequelize 版本中, 定义模型的默认方式涉及使用 sequelize.define. 仍然可以使用它来定义模型, 也可以使用接口在这些模型中添加类型.

注意: 使以下代码与 typescriptDocs/Define.ts 保持同步,以确保其类型检查正确。

import { Sequelize, Model, DataTypes, Optional } from 'sequelize';
const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
// We recommend you declare an interface for the attributes, for stricter typecheckinginterface UserAttributes {  id: number;  name: string;}
// Some fields are optional when calling UserModel.create() or UserModel.build()interface UserCreationAttributes extends Optional<UserAttributes, 'id'> {}
// We need to declare an interface for our model that is basically what our class would beinterface UserInstance  extends Model<UserAttributes, UserCreationAttributes>,    UserAttributes {}
const UserModel = sequelize.define<UserInstance>('User', {  id: {    primaryKey: true,    type: DataTypes.INTEGER.UNSIGNED,  },  name: {    type: DataTypes.STRING,  }});
async function doStuff() {  const instance = await UserModel.findByPk(1, {    rejectOnEmpty: true,  });  console.log(instance.id);}

如果你对模型上非严格的属性检查命令感到满意,则可以通过定义 Instance 来扩展 Model 而无需泛型类型中的任何属性, 从而节省一些代码.

注意: 使以下代码与 typescriptDocs/DefineNoAttributes.ts 保持同步,以确保其类型检查正确。

import { Sequelize, Model, DataTypes } from 'sequelize';
const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
// We need to declare an interface for our model that is basically what our class would beinterface UserInstance extends Model {  id: number;  name: string;}
const UserModel = sequelize.define<UserInstance>('User', {  id: {    primaryKey: true,    type: DataTypes.INTEGER.UNSIGNED,  },  name: {    type: DataTypes.STRING,  },});
async function doStuff() {  const instance = await UserModel.findByPk(1, {    rejectOnEmpty: true,  });  console.log(instance.id);}