TypeScript

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

由于 Sequelize 严重依赖于运行时属性赋值,因此 TypeScript 在开箱即用时不会非常有用. 需要大量的手动类型声明才能使模型可用.

安装

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

  • @types/node (这是普遍需要的)
  • @types/validator
  • @types/bluebird

使用

最简 TypeScript 项目示例:

  1. import { Sequelize, Model, DataTypes, BuildOptions } from 'sequelize';
  2. import { HasManyGetAssociationsMixin, HasManyAddAssociationMixin, HasManyHasAssociationMixin, Association, HasManyCountAssociationsMixin, HasManyCreateAssociationMixin } from 'sequelize';
  3. class User extends Model {
  4. public id!: number; // 注意在严格模式下需要 `null assertion` 或 `!`.
  5. public name!: string;
  6. public preferredName!: string | null; // 可以为空的字段
  7. // 时间戳!
  8. public readonly createdAt!: Date;
  9. public readonly updatedAt!: Date;
  10. // 由于TS无法在编译时确定模型关联,
  11. // 因此我们必须在这里声明它们,
  12. // 实际上这些在调用`Model.init`之前不会存在.
  13. public getProjects!: HasManyGetAssociationsMixin<Project>; // 注意空断言!
  14. public addProject!: HasManyAddAssociationMixin<Project, number>;
  15. public hasProject!: HasManyHasAssociationMixin<Project, number>;
  16. public countProjects!: HasManyCountAssociationsMixin;
  17. public createProject!: HasManyCreateAssociationMixin<Project>;
  18. // 你还可以预先声明可能的包含,
  19. // 只有在你主动包含关系时才会填充这些包含.
  20. public readonly projects?: Project[]; // 请注意,这是可选的,因为它仅在代码中明确请求时填充
  21. public static associations: {
  22. projects: Association<User, Project>;
  23. };
  24. }
  25. const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
  26. class Project extends Model {
  27. public id!: number;
  28. public ownerId!: number;
  29. public name!: string;
  30. public readonly createdAt!: Date;
  31. public readonly updatedAt!: Date;
  32. }
  33. class Address extends Model {
  34. public userId!: number;
  35. public address!: string;
  36. public readonly createdAt!: Date;
  37. public readonly updatedAt!: Date;
  38. }
  39. Project.init({
  40. id: {
  41. type: DataTypes.INTEGER.UNSIGNED, // 你可以省略 `new` 但不鼓励这样做
  42. autoIncrement: true,
  43. primaryKey: true,
  44. },
  45. ownerId: {
  46. type: DataTypes.INTEGER.UNSIGNED,
  47. allowNull: false,
  48. },
  49. name: {
  50. type: new DataTypes.STRING(128),
  51. allowNull: false,
  52. }
  53. }, {
  54. sequelize,
  55. tableName: 'projects',
  56. });
  57. User.init({
  58. id: {
  59. type: DataTypes.INTEGER.UNSIGNED,
  60. autoIncrement: true,
  61. primaryKey: true,
  62. },
  63. name: {
  64. type: new DataTypes.STRING(128),
  65. allowNull: false,
  66. },
  67. preferredName: {
  68. type: new DataTypes.STRING(128),
  69. allowNull: true
  70. }
  71. }, {
  72. tableName: 'address',
  73. sequelize: sequelize, // 这一点很重要
  74. });
  75. Address.init({
  76. userId: {
  77. type: DataTypes.INTEGER.UNSIGNED,
  78. },
  79. address: {
  80. type: new DataTypes.STRING(128),
  81. allowNull: false,
  82. }
  83. }, {
  84. tableName: 'users',
  85. sequelize: sequelize, // 这一点很重要
  86. });
  87. // 在这里,我们关联实际填充预先声明的 `association` 静态方法和其他方法.
  88. User.hasMany(Project, {
  89. sourceKey: 'id',
  90. foreignKey: 'ownerId',
  91. as: 'projects' // 这确定了 `associations` 中的名字!
  92. });
  93. Address.belongsTo(User, {targetKey: 'id'});
  94. User.hasOne(Address,{sourceKey: 'id'});
  95. async function stuff() {
  96. // 请注意,当使用 async/await 时,你将丢失`bluebird` promise上下文,
  97. // 然后你将回到本地
  98. const newUser = await User.create({
  99. name: 'Johnny',
  100. preferredName: 'John',
  101. });
  102. console.log(newUser.id, newUser.name, newUser.preferredName);
  103. const project = await newUser.createProject({
  104. name: 'first!',
  105. });
  106. const ourUser = await User.findByPk(1, {
  107. include: [User.associations.projects],
  108. rejectOnEmpty: true, // 在这里指定 true 会从返回类型中删除`null`!
  109. });
  110. console.log(ourUser.projects![0].name); // 注意`!` null 断言,
  111. // 因为TS无法知道我们是否包含了模型
  112. }

sequelize.define 的用法

当我们使用 sequelize.define 方法定义模型时,TypeScript 不知道如何生成 class 定义. 因此,我们需要做一些手动操作并声明一个接口和一个类型,并最终将 .define 的结果转换为 static 类型.

  1. // 我们需要为我们的模型声明一个接口,基本上就是我们的类
  2. interface MyModel extends Model {
  3. readonly id: number;
  4. }
  5. // 需要声明静态模型,以便`findOne`等使用正确的类型.
  6. type MyModelStatic = typeof Model & {
  7. new (values?: object, options?: BuildOptions): MyModel;
  8. }
  9. // TS无法从 `.define` 调用中获取正确的类定义,因此我们需要在此处进行转换.
  10. const MyDefineModel = <MyModelStatic>sequelize.define('MyDefineModel', {
  11. id: {
  12. primaryKey: true,
  13. type: DataTypes.INTEGER.UNSIGNED,
  14. }
  15. });
  16. function stuffTwo() {
  17. MyDefineModel.findByPk(1, {
  18. rejectOnEmpty: true,
  19. })
  20. .then(myModel => {
  21. console.log(myModel.id);
  22. });
  23. }