提供给 sequelize (v5) 使用的装饰器和一些其他功能。
sequelize-typescript 项目地址
- 安装
- 升级到
sequelize-typescript@1
- 模型定义
- 使用
- 模型关联
- 索引
- Repository 模式
- 模型校验
- 作用域
- Hooks 钩子
- 为何使用
() => Model
? - 风格推荐和限制
sequelize-typescript 依赖 sequelize, 点击查看 sequelize 的 typescript 编码指南 和 reflect-metadata 的详细文档
npm install sequelize
npm install @types/bluebird @types/node @types/validator
npm install reflect-metadata
npm install sequelize-typescript
需要在 tsconfig.json
文件下配置如下项:
"target": "es6", // or a more recent ecmascript version
"experimentalDecorators": true,
"emitDecoratorMetadata": true
sequelize@4
依赖 sequelize-typescript@0.6
. 查看 0.6
版本的
文档 .
npm install sequelize-typescript@0.6
sequelize-typescript@1
只能在 sequelize@5>=
版本下运行。
如果你使用 sequelize@4
或者 sequelize@3
, 请使用 sequelize-typescript@0.6
。
sequelize@5
的破坏性更新同样会影响 sequelize-typescript@1
。
查看 升级到 V5 详情。
sequelize-typescript 目前使用 sequlize 官方的 TypeScript 定义 (点击 查看). 请注意以下事项:
- 绝大部分之前版本 sequelize-typescript 所提供的 interface 被官方所替代
- 不再使用
@types/sequelize
@types/bluebird
不再是一个显式依赖- 官方类型声明没 sequelize-typescript 之前版本的严格
SequelizeConfig
重命名为SequelizeOptions
modelPaths
重命名为models
@Scopes
和 @DefaultScope
装饰器目前接收匿名函数作为参数
@DefaultScope(() => ({...}))
@Scopes(() => ({...}))
已废弃:
@DefaultScope({...})
@Scopes({...}))
sequelize-typescript@1
带来了 repository 模式. 点击 这里 查看详情.
import {Table, Column, Model, HasMany} from 'sequelize-typescript';
@Table
class Person extends Model<Person> {
@Column
name: string;
@Column
birthday: Date;
@HasMany(() => Hobby)
hobbies: Hobby[];
}
模型需要从 Model
类 扩展来,并且需要被装饰器 @Table
所注解。所有在数据库上表现为列属性需要 @Column
注解。
点击 查看 更多进阶示例。
@Table
注解能在不传任何参数的情况下使用,可以通过传入一个对象来指定模型如何定义
(Sequelize 中所有的 模型定义选项 都能使用):
@Table({
timestamps: true,
...
})
class Person extends Model<Person> {}
装饰器 | 描述 |
---|---|
@Table |
自动设置 options.tableName=<CLASS_NAME> 和 options. modelName=<CLASS_NAME> |
@Table(options: DefineOptions) |
按 模型定义选项 设置 (如果没有被模型定义选项所指定的话,会同时设置 options.tableName=<CLASS_NAME> 和 options.modelName=<CLASS_NAME> ) |
主键 (id
) 会从 Model
类中所继承. 这个主键默认被设置为 INTEGER
且
autoIncrement=true
(这种行为是 sequelize 原生的). 这个 id 会被其他标记为主键的值所覆盖。所以请设置 @Column({primaryKey: true})
, 或者同时使用 @PrimaryKey
和 @Column
.
能安全定义 createdAt
, updatedAt
和 deletedAt
属性的注解:
@CreatedAt
creationDate: Date;
@UpdatedAt
updatedOn: Date;
@DeletedAt
deletionDate: Date;
装饰器 | 描述 |
---|---|
@CreatedAt |
设置 timestamps=true 和 createdAt='creationDate' |
@UpdatedAt |
设置 timestamps=true 和 updatedAt='updatedOn' |
@DeletedAt |
设置 timestamps=true , paranoid=true 和 deletedAt='deletionDate' |
@Column
注解能在不传入任何参数下使用,不过传入参数来让 js 类型可以被自行推断是相当有必要的(查看 类型推断 细节).
@Column
name: string;
如果类型不能或者不应该被推断,请使用
import {DataType} from 'sequelize-typescript';
@Column(DataType.TEXT)
name: string;
或者,对于更详细的描述,可以使用对象来描述 (所有的 sequelize 的 模型属性选项 都可以使用):
@Column({
type: DataType.FLOAT,
comment: 'Some value',
...
})
value: number;
装饰器 | 描述 |
---|---|
@Column |
尝试从其 js 类型去定义 数据类型 from js type |
@Column(dataType: DataType) |
手动指定 数据类型 |
@Column(options: AttributeOptions) |
按 模型属性选项 设置 |
如果你喜欢使用装饰器: sequelize-typescript 还提供了更多可供使用. 下面这些装饰器能和 @Column
注解一起使用,来让一些属性更容易使用:
装饰器 | 描述 |
---|---|
@AllowNull(allowNull?: boolean) |
设置 attribute.allowNull (默认为 true ) |
@AutoIncrement |
设置 attribute.autoIncrement=true |
@Unique |
设置 attribute.unique=true |
@Default(value: any) |
设置 attribute.defaultValue 为指定值 |
@PrimaryKey |
设置 attribute.primaryKey=true |
@Comment(value: string) |
设置 attribute.comment 为指定值 |
校验器注解 | 了解 模型校验 |
以下类型能从 javascript 类型上自行推断,其他类型需要需要去手动指定。
数据库数据类型 | Sequelize 数据类型 |
---|---|
string |
STRING |
boolean |
BOOLEAN |
number |
INTEGER |
Date |
DATE |
Buffer |
BLOB |
get/set 访问器 也能正常使用
@Table
class Person extends Model<Person> {
@Column
get name(): string {
return 'My name is ' + this.getDataValue('name');
}
set name(value: string) {
this.setDataValue('name', value);
}
}
除了一些微小的变化, sequelize-typescript 使用起来像原汁原味的 sequelize。 (查阅 sequelize 文档)
为了使定义的模型可用,你必须从 sequelize-typescript
中配置一个 Sequelize
实例 (!).
import {Sequelize} from 'sequelize-typescript';
const sequelize = new Sequelize({
database: 'some_db',
dialect: 'sqlite',
username: 'root',
password: '',
storage: ':memory:',
models: [__dirname + '/models'], // or [Player, Team],
});
在你使用你的模型之前,你必须告诉 sequelize 去那里找到这些模型。所以要么将 models
写到 sequelize 配置中,要么通过调用 sequelize.addModels([Person])
或 sequelize.addModels([__dirname + '/models'])
来添加:
sequelize.addModels([Person]);
sequelize.addModels(['path/to/models']);
import {Sequelize} from 'sequelize-typescript';
const sequelize = new Sequelize({
...
models: [__dirname + '/**/*.model.ts']
});
// or
sequelize.addModels([__dirname + '/**/*.model.ts']);
一个模型通过其文件名与文件匹配。 例如:
// File User.ts matches the following exported model.
export class User extends Model<User> {}
这个是通过把文件名与所有导出的模型所比较来完成的,可以通过指定 modelMatch
函数来自定义模型和文件的匹配。
比方说,如果你的模型被命名为user.model.ts
,而你的类叫做User
,你可以通过使用以下的函数来匹配这两者
import {Sequelize} from 'sequelize-typescript';
const sequelize = new Sequelize({
models: [__dirname + '/models/**/*.model.ts']
modelMatch: (filename, member) => {
return filename.substring(0, filename.indexOf('.model')) === member.toLowerCase();
},
});
对于每一个匹配 *.model.ts
规则的文件,modelMatch
函数会将这个文件导出的所有成员都匹配一遍,例如下面这个文件:
//user.model.ts
import {Table, Column, Model} from 'sequelize-typescript';
export const UserN = 'Not a model';
export const NUser = 'Not a model';
@Table
export class User extends Model<User> {
@Column
nickname: string;
}
modelMatch
函数会匹配全部三个导出的成员
user.model UserN -> false
user.model NUser -> false
user.model User -> true (User 会作为模型被添加)
还有一种匹配模型的方式,就是去使用 export default
来导出
export default class User extends Model<User> {}
⚠️ 当使用路径来添加模型时,一定要记住这些模型会在runtime时被加载,这意味着在开发时和执行时路径有可能会不同。 比方说,使用.ts
扩展名只能和 ts-node 一起使用。
实例化再插入在 sequelize 上是一种将数据保存到数据库的老办法
const person = Person.build({name: 'bob', age: 99});
person.save();
Person.create({name: 'bob', age: 99});
但 sequelize-typescript 提供了一种使用 new
关键字创建实例的方法:
const person = new Person({name: 'bob', age: 99});
person.save();
查询和更新数据也如同使用原生 sequelize 一样,查阅 sequelize 文档 来获取更多细节.
Person
.findOne()
.then(person => {
person.age = 100;
return person.save();
});
Person
.update({
name: 'bobby'
}, {where: {id: 1}})
.then(() => {
});
关联关系可以由模型中的 @HasMany
, @HasOne
, @BelongsTo
, @BelongsToMany
和 @ForeignKey
注解直接阐明。
@Table
class Player extends Model<Player> {
@Column
name: string;
@Column
num: number;
@ForeignKey(() => Team)
@Column
teamId: number;
@BelongsTo(() => Team)
team: Team;
}
@Table
class Team extends Model<Team> {
@Column
name: string;
@HasMany(() => Player)
players: Player[];
}
就这样, sequelize-typescript 把其他所有的事情都帮你做了。 所以当你用 find
来检索这个 team
时,
Team
.findOne({include: [Player]})
.then(team => {
team.players.forEach(player => console.log(`Player ${player.name}`));
})
player
也同样会被解析 (当给 find
传入 include: Player
这个选项时)
@Table
class Book extends Model<Book> {
@BelongsToMany(() => Author, () => BookAuthor)
authors: Author[];
}
@Table
class Author extends Model<Author> {
@BelongsToMany(() => Book, () => BookAuthor)
books: Book[];
}
@Table
class BookAuthor extends Model<BookAuthor> {
@ForeignKey(() => Book)
@Column
bookId: number;
@ForeignKey(() => Author)
@Column
authorId: number;
}
为了安全的访问跨表实例(例如上方代码中的BookAuthor
),关联关系需要手动的设置。
Author
模型就可以这样来设置:
@BelongsToMany(() => Book, () => BookAuthor)
books: Array<Book & {BookAuthor: BookAuthor}>;
对于 一对一 的关系,使用@HasOne(...)
(关联的外键会被创建于另一个模型) 和 @BelongsTo(...)
(关联的外键会被创建于本模型)
装饰器 | 描述 |
---|---|
@ForeignKey(relatedModelGetter: () => typeof Model) |
将相关类的属性标记为 foreignKey |
@BelongsTo(relatedModelGetter: () => typeof Model) |
sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from source class |
@BelongsTo(relatedModelGetter: () => typeof Model, foreignKey: string) |
sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value |
@BelongsTo(relatedModelGetter: () => typeof Model, options: AssociationOptionsBelongsTo) |
sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and options are additional association options |
@HasMany(relatedModelGetter: () => typeof Model) |
sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from target related class |
@HasMany(relatedModelGetter: () => typeof Model, foreignKey: string) |
sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value |
@HasMany(relatedModelGetter: () => typeof Model, options: AssociationOptionsHasMany) |
sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and options are additional association options |
@HasOne(relatedModelGetter: () => typeof Model) |
sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from target related class |
@HasOne(relatedModelGetter: () => typeof Model, foreignKey: string) |
sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value |
@HasOne(relatedModelGetter: () => typeof Model, options: AssociationOptionsHasOne) |
sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and options are additional association options |
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model)) |
sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property and foreignKey /otherKey is resolved from through class |
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model), foreignKey: string) |
sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property, foreignKey is explicitly specified value and otherKey is resolved from through class |
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model), foreignKey: string, otherKey: string) |
sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property and foreignKey /otherKey are explicitly specified values |
@BelongsToMany(relatedModelGetter: () => typeof Model, through: string, foreignKey: string, otherKey: string) |
sets SourceModel.belongsToMany(RelatedModel, {through: throughString, ...}) while as is key of annotated property and foreignKey /otherKey are explicitly specified values |
@BelongsToMany(relatedModelGetter: () => typeof Model, options: AssociationOptionsBelongsToMany) |
sets SourceModel.belongsToMany(RelatedModel, {through: throughString, ...}) while as is key of annotated property and options are additional association values, including foreignKey and otherKey . |
请注意当使用 AssociationOptions
时,某些属性会在关联关系建立时被 reflection metadata
或 传入的属性所覆盖。
For example, as
will always be the annotated property's name, and through
will be the explicitly stated value.
sequelize-typescript 通过识别响应的类的引用来解析外键。 所以说如果你像下方代码一样来建立多重关联:
@Table
class Book extends Model<Book> {
@ForeignKey(() => Person)
@Column
authorId: number;
@BelongsTo(() => Person)
author: Person;
@ForeignKey(() => Person)
@Column
proofreaderId: number;
@BelongsTo(() => Person)
proofreader: Person;
}
@Table
class Person extends Model<Person> {
@HasMany(() => Book)
writtenBooks: Book[];
@HasMany(() => Book)
proofedBooks: Book[];
}
sequelize-typescript 不知道去使用哪一个外键去建立对应关联,所以你需要像下方代码一样去明确外键:
// in class "Books":
@BelongsTo(() => Person, 'authorId')
author: Person;
@BelongsTo(() => Person, 'proofreaderId')
proofreader: Person;
// in class "Person":
@HasMany(() => Book, 'authorId')
writtenBooks: Book[];
@HasMany(() => Book, 'proofreaderId')
proofedBooks: Book[];
当模型关联创建时,sequelize 会在对应的模型上绑定一些方法。所以在modelA
和 modelB
间创建一对多的关系时,modelA
的实例将会存在 getModelBs
, setModelBs
, addModelB
, removeModelB
, hasModelB
这些方法。这些同样可以在 sequelize-typescript 中使用,但在你访问 getModelB
, setModelB
或者
addModelB
时,Typescript 没办法正常的识别他们。为了在使用 TypeScript 时更加友好,sequelize-typescript 中的 Model.prototype
具有 $set
, $get
, $add
这几个函数。
@Table
class ModelA extends Model<ModelA> {
@HasMany(() => ModelB)
bs: ModelB[];
}
@Table
class ModelB extends Model<ModelB> {
@BelongsTo(() => ModelA)
a: ModelA;
}
如果要使用这些方法,请将该关联对应的键值作为第一个参数传入:
const modelA = new ModelA();
modelA.$set('bs', [ /* instance */]).then( /* ... */);
modelA.$add('b', /* instance */).then( /* ... */);
modelA.$get('bs').then( /* ... */);
modelA.$count('bs').then( /* ... */);
modelA.$has('bs').then( /* ... */);
modelA.$remove('bs', /* instance */ ).then( /* ... */);
modelA.$create('bs', /* value */ ).then( /* ... */);
@Index
注解能在不传入任何参数的情况下使用。
@Table
class Person extends Model<Person> {
@Index // 用默认名称定义一个索引
@Column
name: string;
@Index // 定义另一个索引
@Column
birthday: Date;
}
通过传递对象来指定索引的相关设置 (查看 索引定义选项 文档):
@Table
class Person extends Model<Person> {
@Index('my-index') // 给 name 和 birthday 定义多列索引
@Column
name: string;
@Index('my-index') // 把 birthday 字段添加到 my-index 索引
@Column
birthday: Date;
@Index({
// index options
name: 'job-index',
parser: 'my-parser',
type: 'UNIQUE',
unique: true,
where: { isEmployee: true },
concurrently: true,
using: 'BTREE',
operator: 'text_pattern_ops',
prefix: 'test-',
// index field options
length: 10,
order: 'ASC',
collate: 'NOCASE',
})
@Column
jobTitle: string;
@Column
isEmployee: boolean;
}
Decorator | Description |
---|---|
@Index |
把被装饰的字段名作为新索引添加到 options.indexes |
@Index(name: string) |
添加新的索引或将字段添加到指定名称的现有索引中 |
@Table(options: IndexDecoratorOptions) |
通过 配置 来设置索引和索引字段 |
createIndexDecorator()
函数能用来创建一个自定义装饰器,这个装饰器支持通过指定的属性来设置索引,传入装饰器的参数将被用来配置索引字段。
const SomeIndex = createIndexDecorator();
const JobIndex = createIndexDecorator({
// index options
name: 'job-index',
parser: 'my-parser',
type: 'UNIQUE',
unique: true,
where: { isEmployee: true },
concurrently: true,
using: 'BTREE',
operator: 'text_pattern_ops',
prefix: 'test-',
});
@Table
class Person extends Model<Person> {
@SomeIndex // Add name to SomeIndex
@Column
name: string;
@SomeIndex // Add birthday to SomeIndex
@Column
birthday: Date;
@JobIndex({
// index field options
length: 10,
order: 'ASC',
collate: 'NOCASE',
})
@Column
jobTitle: string;
@Column
isEmployee: boolean;
}
repository 模式可以把一些类似 find
, create
等的静态方法从模型定义中分离出来,并且赋予了模型可以和多个 sequelize 实例一起使用的能力。
通过设置 repositoryMode
字段来开启 repository 模式:
const sequelize = new Sequelize({
repositoryMode: true,
...,
});
通过操作 repository 来进行创建实例和查询的操作:
const userRepository = sequelize.getRepository(User);
const luke = await userRepository.create({name: 'Luke Skywalker'});
const luke = await userRepository.findOne({where: {name: 'luke'}});
目前需要在使用 repository 时通过配置 include
参数来进行检索或创建相关数据
const userRepository = sequelize.getRepository(User);
const addressRepository = sequelize.getRepository(Address);
userRepository.find({include: [addressRepository]});
userRepository.create({name: 'Bear'}, {include: [addressRepository]});
⚠️ 未来会有变动:开发者应该去引用模型类而不是 repository
当同时使用 @Scope
注解和 repository 模式时,嵌套作用域和 include
通常将不起作用
@Scopes(() => ({
// includes
withAddress: {
include: [() => Address],
},
// nested scopes
withAddressIncludingLatLng: {
include: [() => Address.scope('withLatLng')],
}
}))
@Table
class User extends Model<User> {}
⚠️ 未来会有变动: 单一的include
将被实现
校验项可以在 @Column
注解中设置,不过如果你更偏爱单独的装饰器来校验的话,你可以通过添加校验装饰器来实现:
比方说 validate.isEmail=true
写作 @IsEmail
、validate.equals='value'
写作 @Equals('value')
以此类推。
需要注意的是,一个期望布尔值的校验器会被编译为一个不接收参数的注解。
查阅 sequelize 文档 来了解所有的校验规则。
下面的校验器不能被简单的从一个 sequelize 校验器转换成修饰器:
校验器 | 注解 |
---|---|
validate.len=[number, number] |
@Length({max?: number, min?: number}) |
validate[customName: string] |
自定义校验器可使用 @Is(...) 注解: @Is('custom', (value) => { /* ... */}) 或 @Is(function custom(value) { /* ... */}) |
const HEX_REGEX = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
@Table
export class Shoe extends Model<Shoe> {
@IsUUID(4)
@PrimaryKey
@Column
id: string;
@Equals('lala')
@Column
readonly key: string;
@Contains('Special')
@Column
special: string;
@Length({min: 3, max: 15})
@Column
brand: string;
@IsUrl
@Column
brandUrl: string;
@Is('HexColor', (value) => {
if (!HEX_REGEX.test(value)) {
throw new Error(`"${value}" is not a hex color value.`);
}
})
@Column
primaryColor: string;
@Is(function hexColor(value: string): void {
if (!HEX_REGEX.test(value)) {
throw new Error(`"${value}" is not a hex color value.`);
}
})
@Column
secondaryColor: string;
@Is(HEX_REGEX)
@Column
tertiaryColor: string;
@IsDate
@IsBefore('2017-02-27')
@Column
producedAt: Date;
}
作用域同样能使用装饰器来定义。作用域配置同原生 sequelize (查阅 sequelize 文档 来了解作用域用法)
@DefaultScope(() => ({
attributes: ['id', 'primaryColor', 'secondaryColor', 'producedAt']
}))
@Scopes(() => ({
full: {
include: [Manufacturer]
},
yellow: {
where: {primaryColor: 'yellow'}
}
}))
@Table
export class ShoeWithScopes extends Model<ShoeWithScopes> {
@Column
readonly secretKey: string;
@Column
primaryColor: string;
@Column
secondaryColor: string;
@Column
producedAt: Date;
@ForeignKey(() => Manufacturer)
@Column
manufacturerId: number;
@BelongsTo(() => Manufacturer)
manufacturer: Manufacturer;
}
Hooks(也称为生命周期事件)是在执行 sequelize 中的调用之前和之后调用的函数,所有模型上钩子都被支持。 查阅 相关的单元测试 来获得总结。
每一个钩子都必须为一个 static
方法,多个钩子可以被关联到一个方法,同时你也可以给一个钩子定义多个方法。
方法的函数名不能和钩子的函数名相同(比方说, @BeforeCreate
钩子不能被命名为 beforeCreate
,因为这个名称的方法被 Sequelize 预定义过了)
@Table
export class Person extends Model<Person> {
@Column
name: string;
@BeforeUpdate
@BeforeCreate
static makeUpperCase(instance: Person) {
// this will be called when an instance is created or updated
instance.name = instance.name.toLocaleUpperCase();
}
@BeforeCreate
static addUnicorn(instance: Person) {
// this will also be called when an instance is created
instance.name += ' 🦄';
}
}
既然 @ForeignKey(Model)
可读性更高, 那么为什么要使用 @ForeignKey(() => Model)
呢? 当发生循环依赖时,Model
会为 undefined
(通常 node 会为你解决)。当他被传递给 @ForeignKey
时,我们通过使用一个返回了实际模型的函数来避免这个问题的发生。
除非你使用 repository 模式, 你不能向连接配置不同的 Sequelize 实例添加一个相同模型。所以,一个模型仅适用于一个 Sequelize 连接。
这不仅仅是一个架构设计的好习惯,并且有利于命令的执行。由于 TypeScript 根据 emitDecoratorMetadata
这个编译选项创建了 __metadata("design:type", SomeModel)
,在某些情况下, SomeModel
有可能没有被定义(不是 undefined!),并且会出一个 ReferenceError
。当把 SomeModel
放进一个单独的文件中,就相当于 __metadata("design:type", SomeModel_1.SomeModel)
,这样的话就不会报错。
如果你有压缩代码的需求,为了 @Table
注解能正常使用,你需要设置在 @DefineOptions
中设置 tableName
和 modelName
。sequelize-typescript 会使用 tableName
和 modelName
作为类的默认名称。当代码被压缩后,类名将不再是最初定义的那个了。(就像 class User
会变成 class b
)
如果你想对这个开源项目贡献出自己的一份力量,你可以:
- 提交 issue 或者 参与其他 issue 的讨论
- Fork 这个项目来提交 PR
- 丰富 Sequelize 的类型声明.
- 提出任何有建设性的建议
为了提交一个PR,请:
- 创建一个新的分支.
- 完整的跑一遍测试流程 (
npm install && npm run build && npm run cover
) 并且确保你的提交能顺利通过测试。 - 通过 commit 中的 message、详细的 PR 说明,必要时的代码注释等等来记录你的工作
如果你想丰富 Sequelize 的类型声明,请去 类型定义仓库,向 sequelize 提交一个 PR 也是一个好方法,那样子 Sequlize 就能维护自己的类型声明,不过这样也许比更新微软的类型声明库要更难。TypeScript 团队正在尝试去慢慢的鼓励 npm 包维护者去维护自己的类型声明,但 TypeScript 还是会有专门的人员去维护 DT repo,审核PR,来保证高质量。
如果你发现文档中有哪些翻译的晦涩,或者不合理的地方,欢迎通过 issue 或者 PR 的方式来帮助改进
请牢记, sequelize-typescript
不提供 sequelize
的类型声明 - 这是不相关联的事情
sequelize-typescript
参数中的许多类型都引用或扩展都是 sequelize 已经拥有的内容。