mongoose-tsgen-feathers
v1.3.0
Published
A Typescript interface generator for Mongoose that works out of the box.
Downloads
5
Maintainers
Readme
mongoose-tsgen
An out-of-the-box Typescript interface generator for Mongoose.
Features
- [x] Automatically generate an
index.d.ts
file containing Typescript interfaces for each Mongoose document, model and subdocument - [x] Works out of the box, don't need to rewrite your schemas
- [x] Add custom interfaces (i.e. a subset of a document for use by a client)
- [x] Multiple search patterns and import strategies to require minimal input and configuration
Compatibility
- [x] All Mongoose types and arrays
- [x] Virtual properties
- [x] Both Typescript and Javascript schema files (if using Javascript, you will want to convert to Typescript upon generating the
index.d.ts
file) - [x] Typescript path aliases
- [x] Mongoose method and static functions - These could be improved, they currently get typed as
Function
without parameter and return types - [ ] Support for
Model.Create
. Currentlynew Model
must be used. - [ ] Setting subdocument arrays without casting to
any
(currently you need to douser.friends = [{ uid, name }] as any
).
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
// NOTE: you will need to import these types after your first ever run of the CLI
// See the 'Initializing Schemas' section
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"
}
}
});
// NOTE: `this: IUser` and `this: IUserModel` is to tell TS the type of `this' value using the "fake this" feature
// you will need to add these in after your first ever run of the CLI
UserSchema.virtual("name").get(function(this: IUser) { return `${this.firstName} ${this.lastName}` });
// method functions
UserSchema.methods = {
isMetadataString(this: IUser) { return typeof this.metadata === "string"; }
}
// static functions
UserSchema.statics = {
// friendUids could also use the type `ObjectId[]` here
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
// ######################################## THIS FILE WAS GENERATED BY MONGOOSE-TSGEN ######################################## //
// NOTE: ANY CHANGES MADE WILL BE OVERWRITTEN ON SUBSEQUENT EXECUTIONS OF MONGOOSE-TSGEN.
// TO ADD CUSTOM INTERFACES, DEFINE THEM IN THE `custom.d.ts` FILE.
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 interface from mongoose module
import { IUser } from "mongoose"
async function getUser(uid: string): IUser {
// user will be of type IUser
const user = await User.findById(uid);
return user;
}
async function editEmail(user: IUser, newEmail: string): IUser {
user.email = newEmail;
return await user.save();
}