在之前使用Mongoose和Typesript进行开发的时候,必须同时定义Mongoose中Model和Typescript中的interface,像这样:
interface Car {
model?: string;
}
interface Job {
title?: string;
position?: string;
}
interface User {
name?: string;
age: number;
job?: Job;
car: Car | string;
}
mongoose.model('User', {
name: String,
age: { type: Number, required: true },
job: {
title: String;
position: String;
},
car: { type: Schema.Types.ObjectId, ref: 'Car' }
});
mongoose.model('Car', {
model: string,
});
这样做的话,如果数据的Model有改变,那么定义的Typescript的interface也要跟着改变,这样对于开发修改代码的体验是非常差的。
Typescript使用类和注解的方式来解决这个问题,上面的代码可以改成:
class Job {
@prop()
title?: string;
@prop()
position?: string;
}
class Car extends Typegoose {
@prop()
model?: string;
}
class User extends Typegoose {
@prop()
name?: string;
@prop({ required: true })
age!: number;
@prop()
job?: Job;
@prop({ ref: Car })
car?: Ref<Car>;
}
其中对于每一个数据Model会有一个类来进行对应,类中的每一个属性会有对应的Typescript类型和相应的装饰器(比如上例中的@props
)。在装饰器中会有对应的Model中的规定的属性(如required
和ref
等);而对应的Typescript类型则承担了之前定义的interface的责任。最后我们可以通过getModelForClass
来生成真正的Mongooses数据模型。
对应Mongoose数据模型中的每一个属性,在类中都需要用@props()
进行修饰。
和Mongoose类似,其中装饰器中的options常见的选项有:
同@props,不过对应地声明该属性是一个数组。
其中options常见的选项有:
类似于hook,可以定义在数据增删查改之前进行一些操作。
// 在一条Car数据写入数据库之前进行回调函数中的操作
@pre<Car>('save', function(next) {
if (this.model === 'Tesla') {
this.isFast = true;
}
next();
})
class Car extends Typegoose {
@prop({ required: true })
model!: string;
@prop()
isFast?: boolean;
}
用法类似于@pre
。
该方法会通过传入参数中的类生成对应的Mongoose的Model。(类似于mongoose.model
通过schema生成)
const CarModel = getModelForClass(Car)
以上为个人在开发学习时使用到的一些Typegoose常见方法等的记录,具体更多可以看下面参考资料: