为什么egg-mongoose不能提供类型支持
我们查看egg- mongoose对egg的扩展,进入/node_modules/egg-mongoose/index.d.ts,我们看到egg-mongoose对egg进行了两个扩展
import * as mongoose from 'mongoose';
declare module 'egg' {
type MongooseModels = {
[key: string]: mongoose.Model<any>
};
type MongooseSingleton = {
clients: Map<string, mongoose.Connection>,
get (id: string) : mongoose.Connection
};
type MongooseConfig = {
url: string,
options?: mongoose.ConnectionOptions
};
// extend app
interface Application {
mongooseDB: mongoose.Connection | MongooseSingleton;
mongoose: typeof mongoose;
model: MongooseModels;
}
// extend context
interface Context {
model: MongooseModels;
}
// extend your config
interface EggAppConfig {
mongoose: {
url?: string,
options?: mongoose.ConnectionOptions,
client?: MongooseConfig,
clients?: {
[key: string]: MongooseConfig
}
};
}
}
分别在20行(Application)和27行(Context),两个interface都扩展了model属性,类型为MongooseModels。而在第5行(type MongooseModels),我们看到MongooseModels是一个key:value形式的对象,key和value都有不确定性,这是导致ctx.model无法类型推断的原因。
如何扩展eggjs的类型定义
egg为我们提供了一个目录,该目录为 TS 的规范,在里面的 **/*.d.ts 文件将被自动识别。
- 开发者需要手写的建议放在 typings/index.d.ts 中。
- 工具会自动生成 typings/{app,config}/**.d.ts ,请勿自行修改,避免被覆盖。
需要处理的问题
type MongooseModels = {
[key: string]: mongoose.Model<any>
};
我们需要将MongooseModels进行修改
- 将model的名称对应为[key]
- 将mongoose.Model中的any替换为model中定义的props,也就是将T=any变得明确
import 'egg';
import {Connection,Model} from 'mongoose'
//定义的model属性
import {UserProps} from '../app/model/user'
declare module 'egg' {
interface MongooseModels{
User:Model<UserProps>
}
}
如何自动生成
egg默认使用了egg-ts-helper为我们做了如下支持
// This file is created by egg-ts-helper@1.33.0
// Do not modify this file!!!!!!!!!
import 'egg';
import ExportUser from '../../../app/model/user';
declare module 'egg' {
interface IModel {
User: ReturnType<typeof ExportUser>;
}
}
egg-ts-helper默认导入了model下的所有文件,并将其类型重载到IModel上,我们可以通过将MongooseModels类型扩展为IModel达到自动创建类型支持
import 'egg';
import { Model } from 'mongoose'
declare module 'egg' {
interface MongooseModels extends IModel {
[key: string]: Model<any>
}
}
总结
我们最开始通过手动书写MongooseModels的属性来达到类型支持的目的,然而这种方式过于繁琐,需要我们手动去导入各个model。我们发现egg-ts-helper已经为我们自动导入了所有的model,此时可以通过将MongooseModels extends IModel,从而为egg-mongoose本身添加明确的类型定义。