定义一个模型
我们要定义一个模型,首先我们会用到define
, 它的返回值类似是 Model<TInstance, TAttributes>
。
define<TInstance, TAttributes>(modelName: string, attributes: DefineAttributes,
options?: DefineOptions<TInstance>): Model<TInstance, TAttributes>;
在 defined 方法中, <TInstance, TAttributes>
这俩泛型会传给 Model
。泛型是用来解决描述某一类型,且在定义之前,无法明确知道某一变量的类型的问题。换句话说,就是函数的返回值,要依赖你传递进来的对象的类型。函数的括号 ()
传递的是参数,泛型的 <>
则是传递描述类型。接下来我们继续看 Model
的定义。
interface Model<TInstance, TAttributes> extends Hooks<TInstance>, Associations {}
接口是支持继承的,接口是描述一个对象的属性与方法,并且进行约束。此时 Model 具有 Hooks,Associations 的描述。Associations
里面包含定义模型直接关系的一些方法,Hooks
是定义模型生命周期的一些方法(删除数据之前,删除方法之后,创建方法之后….等等)。然后我们在 Model
方法里面,我们可以看到很多返回值为TInstance
的类型的函数。
比如
build(record?: TAttributes, options?: BuildOptions): TInstance;
build
是创建一个实例的方法,它会返回 TInstance
,也就是说这个 TInstance
这个类型 (interface) 要我们自己来写。
1.用 interface 声明一下模型有哪些属性,且是何种类型
interface UserAttributes {
email: string;
name: string;
}
2.声明一个描述模型的实例变量的类型,表明可以访问的属性和方法
interface UserInstance extends Sequelize.Instance<UserAttributes> {
id: number;
createdAt: Date;
updatedAt: Date;
email: string;
name: string;
}
FAQ: 为什么要继承
Sequelize.Instance<UserAttributes>
呢?Sequelize.Instance
里面定义了一些所有模型实例通用的方法,而且我们还需要把UserAttributes
(我们自定义的属性) 给传递进去。FAQ: 你为什么知道需要继承
Sequelize.Instance
?因为我发现不继承的话,通过build
能访问的方法里面根本就没有官方 API 里面所说的那些方法。这里我说的没有方法是指 TypeScript 这一个层面没有,假如通过(use as any)去调用,还是可以调用得到的,只是 TypeScript 这一层没有代码提示了而已。当我遇到这个问题之后,我就想看看老外是如何写的,所以我就直接通过百度typescript sequelize
就搜索得到了,之后我又进入 d.ts 文件里面去看了一下Instance
这个接口。
这里我还遇见了一个问题那就这个模型没法使用 new
关键字,因为没有constructor
构造器,也没有 prototype
,当然这里说的没有,也是在 typescript
这个层面。对于一切报类型错误的大家都可以用 变量 as any
,来解决问题,也就是类型断言,断言为兼容所有类型的类型即可,也可以说是万能类型。
我们还可以深入看一下 Instance
接口,在 2724 - 2922
行,这里面都是它可以访问的方法。
3.定义模型
const S = Sequelize
const User = sequelize.define<UserInstance, UserAttributes>
('User', {
email: S.STRING,
name: S.STRING
});
之前我们定义的属性,id
、createdAt
、updateAt
是 sequelize 默认生成的,当然也可以通过配置项关闭自动时间戳(创建的时间,修改的时间),或者自己定义 id 的类型与约束,sequelize 会有限以你的配置为标准。像上面我们就没有传递 id 的类型与约束,sequelize 就给我们自动补上了,因为一个表是不可能没有主键的。
4.给模型定义一些方法
(User as any).prototype.say = function(this: UserInstance) {
console.log('name ' + this.name);
}
Tip:有3点,我们需要注意一下。
- (User as any) 避免报错
- 使用的是 function(){} 来保存 this 指向,假如使用箭头函数,则 this 为空。
- this: UserInstance 在第一个参数的位置,可以指定 this 的类型,这样 this 就有的代码提示。
5.运行
async function main() {
try {
await User.sync();
const user = User.build({ name: 'yugo', email: 'soome@gmail.com' });
await user.save();
// -----------------------
// const user = await User.findAll();
// (user[0] as any).say()
process.exit(0)
}catch(e){
console.log(e)
}
}
main()
await
后面跟一个 Promise 对象,像sync
和save
返回值其实都是一个 Promise 对象。sync
将我们 User 的模型同步到数据库表格,build
会创建一个模型实例,但并不会存储,需要自行调用save
方法,或者调用create
方法,它会直接存储。之后我们通过ts-node index.ts
进行运行,当有数据了之后,我们再解开后俩句的注释,注释前三句,再次运行测试一下查询是否正常。