mongoose-tsgen
An out-of-the-box Typescript interface generator for Mongoose.
Features
Compatibility
Would love any help with the last few listed features above.
Installation
$ npm install -D mongoose-tsgen
$ npx mtgen --help # print usage
Usage
mtgen [ROOT_PATH]
Generate an index.d.ts file containing Mongoose Schema interfaces.
USAGE
$ mtgen [ROOT_PATH - default = "."]
OPTIONS
-d, --dry-run print output rather than writing to file
-h, --help show CLI help
-j, --js search for Mongoose schemas in Javascript files rather than in Typescript files
-o, --output=output [default: ./src/types/mongoose] path of output index.d.ts file
-p, --project=project [default: ./] path of tsconfig.json or its root folder
All sub-directories of ROOT_PATH
will be searched for a /models/
folder. If such folder contains an index.ts
(or index.js
) file, all Mongoose models are expected to be exported from here. If such file does not exist, all *.ts
(or *.js
) files in this folder are expected to export a Mongoose model.
NOTE: --output requires a folder path or a file path ending in index.d.ts
. If the path does not exist, it will be created.
See code: src/index.ts
Example
./src/models/user.ts
import mongoose, { IUser, IUserModel } from "mongoose";
const { Schema } = mongoose;
const UserSchema = new Schema({
email: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
metadata: Schema.Types.Mixed,
friends: [
{
uid: {
type: Schema.Types.ObjectId,
ref: "User",
required: true
},
nickname: String
}
],
city: {
coordinates: {
type: [Number],
index: "2dsphere"
}
}
});
UserSchema.virtual("name").get(function(this: IUser) { return `${this.firstName} ${this.lastName}` });
UserSchema.methods = {
isMetadataString(this: IUser) { return typeof this.metadata === "string"; }
}
UserSchema.statics = {
async getFriends(this: IUserModel, friendUids: IUser["_id"][]) {
return await this.aggregate([ { $match: { _id: { $in: friendUids } } } ]);
}
}
export const User: IUserModel = mongoose.model<IUser, IUserModel>("User", UserSchema);
export default User;
generate interfaces
$ mtgen
generated interface file ./src/types/mongoose/index.d.ts
import mongoose from "mongoose";
type ObjectId = mongoose.Types.ObjectId;
declare module "mongoose" {
interface IUserFriend extends mongoose.Types.Subdocument {
uid: IUser["_id"] | IUser;
nickname?: string;
}
export interface IUserModel extends Model<IUser> {
getFriends: Function;
}
export interface IUser extends Document {
email: string;
metadata?: any;
firstName: string;
lastName: string;
friends: Types.DocumentArray<IUserFriend>;
cityCoordinates?: Types.Array<number>;
name: any;
isMetadataString: Function;
}
}
Initializing Schemas
Once you've generated your index.d.ts file, all you need to do is add the following types to your schema definitions:
user.ts before:
import mongoose from "mongoose";
const UserSchema = new Schema(...);
export const User = mongoose.model("User", UserSchema);
export default User;
user.ts after:
import mongoose, { IUser, IUserModel } from "mongoose";
const UserSchema = new Schema(...);
export const User: IUserModel = mongoose.model<IUser, IUserModel>("User", UserSchema);
export default User;
Then you can import the interfaces across your application from the Mongoose module and use them for document types:
import { IUser } from "mongoose"
async function getUser(uid: string): IUser {
const user = await User.findById(uid);
return user;
}
async function editEmail(user: IUser, newEmail: string): IUser {
user.email = newEmail;
return await user.save();
}