mongoose-tsgen-feathers
TypeScript icon, indicating that this package has built-in type declarations

1.3.0 • Public • Published

mongoose-tsgen

An out-of-the-box Typescript interface generator for Mongoose.

oclif Version npm License

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. Currently new Model must be used.
  • [ ] Setting subdocument arrays without casting to any (currently you need to do user.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();
}

Package Sidebar

Install

npm i mongoose-tsgen-feathers

Weekly Downloads

5

Version

1.3.0

License

MIT

Unpacked Size

44.9 kB

Total Files

14

Last publish

Collaborators

  • alex-rokabilis