{"id":23777307,"url":"https://github.com/francescov1/mongoose-tsgen","last_synced_at":"2025-04-12T01:07:05.688Z","repository":{"id":38667885,"uuid":"297461339","full_name":"francescov1/mongoose-tsgen","owner":"francescov1","description":"A plug-n-play Typescript generator for Mongoose.","archived":false,"fork":false,"pushed_at":"2025-02-09T01:51:38.000Z","size":2801,"stargazers_count":106,"open_issues_count":4,"forks_count":26,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-12T01:06:58.174Z","etag":null,"topics":["generator","mongodb","mongoose","mongoose-types","nodejs","orm","ts","typescript","typescript-interfaces"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/francescov1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-21T21:06:39.000Z","updated_at":"2025-04-08T15:39:53.000Z","dependencies_parsed_at":"2023-11-25T19:27:12.912Z","dependency_job_id":"9e5b7f5b-9e36-41f2-abd9-02f808d3fb94","html_url":"https://github.com/francescov1/mongoose-tsgen","commit_stats":{"total_commits":438,"total_committers":6,"mean_commits":73.0,"dds":0.0365296803652968,"last_synced_commit":"fa5f18d4e571e5e835fc26a2b3e8ce01032a0c15"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francescov1%2Fmongoose-tsgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francescov1%2Fmongoose-tsgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francescov1%2Fmongoose-tsgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/francescov1%2Fmongoose-tsgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/francescov1","download_url":"https://codeload.github.com/francescov1/mongoose-tsgen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248501861,"owners_count":21114683,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["generator","mongodb","mongoose","mongoose-types","nodejs","orm","ts","typescript","typescript-interfaces"],"created_at":"2025-01-01T08:24:26.182Z","updated_at":"2025-04-12T01:07:05.671Z","avatar_url":"https://github.com/francescov1.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mongoose-tsgen\n\nA plug-n-play Typescript generator for Mongoose.\n\n[![Version](https://img.shields.io/npm/v/mongoose-tsgen.svg)](https://npmjs.org/package/mongoose-tsgen)\n[![npm](https://img.shields.io/npm/dt/mongoose-tsgen)](https://www.npmjs.com/package/mongoose-tsgen)\n[![License](https://img.shields.io/npm/l/mongoose-tsgen.svg)](https://github.com/francescov1/mongoose-tsgen/blob/master/package.json)\n\n\u003c!-- [![Downloads/week](https://img.shields.io/npm/dw/mongoose-tsgen.svg)](https://npmjs.org/package/mongoose-tsgen) --\u003e\n\n\u003c!-- toc --\u003e\n\n- [Motivation](#motivation)\n- [Features](#features)\n- [Compatibility](#compatibility)\n- [Installation](#installation)\n- [The Gist](#the-gist)\n- [Usage](#usage)\n- [Example](#example)\n- [Known Issues](#known-issues)\n- [Development](#Development)\n\u003c!-- tocstop --\u003e\n\n# Motivation\n\nUsing Mongoose with Typescript requires duplicating Mongoose Schemas using Typescript interfaces. To avoid duplication, libraries like [typegoose](https://github.com/typegoose/typegoose) define a custom schema syntax that is used to generate both the Mongoose Schemas and the Typescript interfaces. Unfortunately, this requires users to completely rewrite their Mongoose Schemas into an unfamiliar syntax and does not support the entire Mongoose feature set.\n\nThis library aims to remove these drawbacks by instead parsing your already-written Mongoose Schemas and generating associated Typescript interfaces. This removes the need to learn new syntax and makes this library extremely simple to integrate into an existing Mongoose project.\n\n# Features\n\n- 😌 Automatically generate Typescript typings for each Mongoose document, model and subdocument\n- 📦 Works out of the box, don't need to rewrite your schemas\n- ⛑ Type-safe [population](#query-population)\n- ➕ Includes a \"Mongoose-less\" version of each schema interface (Mongoose typings removed)\n\n# Compatibility\n\n- ✅ All Mongoose types, arrays and maps\n- ✅ Virtual properties\n- ✅ Mongoose method, static \u0026 query functions\n- ✅ Multiple schemas per file\n- ✅ Typescript path aliases\n\n### Mongoose version\n\nFind your Mongoose version below and install the associated mongoose-tsgen version. Ensure to refer to each version's respective README for documentation (hyperlinked in table).\n\n| mongoose       | mongoose-tsgen |\n| -------------- | -------------- |\n| 6.1.5+         | latest         |\n| 5.11.19-6.1.14 | [8.4.7](https://github.com/francescov1/mongoose-tsgen/blob/e002649ad8649e26ee372ef964458934a555d2eb/README.md)          |\n| 5.11.0-5.11.18 | [7.1.3](https://github.com/francescov1/mongoose-tsgen/blob/85ccc70b13e875b0de135a171563292fa58e5472/README.md)          |\n| \u003c5.11.0        | [6.0.10](https://github.com/francescov1/mongoose-tsgen/blob/12d2f693957f61776d5b6addf23a8b051c99294c/README.md)         |\n\n\u003e Note: For Mongoose `v6.3.2 - v6.4.0`, see [Known Issues](#known-issues) first.\n\n# Installation\n\nmongoose-tsgen can be installed globally or locally as a dev dependency. Refer to the table above to ensure you are using the correct version.\n\n```bash\n# install with npm or yarn\nnpm install -D mongoose-tsgen\n\n# install mongoose-tsgen v7.1.3 for mongoose v5.10.19 (see table above for compatibility)\nnpm install -D mongoose-tsgen@7.1.3\n\n# install with yarn\nyarn add -D mongoose-tsgen\n```\n\n# The Gist\n\nOnce you've generated your typings file (see [Usage](#usage)), all you need to do is use the generated types in your schema definitions and throughout your project. \n\n### user.ts before:\n\n```typescript\nimport mongoose from \"mongoose\";\n\nconst UserSchema = new Schema(...);\n\nexport const User = mongoose.model(\"User\", UserSchema);\n```\n\n### user.ts after:\n\n```typescript\nimport mongoose from \"mongoose\";\nimport { UserDocument, UserModel, UserSchema } from \"../interfaces/mongoose.gen.ts\";\n\nconst UserSchema: UserSchema = new Schema(...);\n\nexport const User: UserModel = mongoose.model\u003cUserDocument, UserModel\u003e(\"User\", UserSchema);\n```\n\nThen you can import the typings across your application from the Mongoose module and use them for document types:\n\n```typescript\nimport { UserDocument } from \"./interfaces/mongoose.gen.ts\";\n\nasync function getUser(uid: string): UserDocument {\n  // user will be of type User\n  const user = await User.findById(uid);\n  return user;\n}\n\nasync function editEmail(user: UserDocument, newEmail: string): UserDocument {\n  user.email = newEmail;\n  return await user.save();\n}\n```\n\nNote that this practice is well documented online, I've found the following two Medium articles especially useful:\n- [Complete guide for Typescript with Mongoose for Node.js](https://medium.com/@agentwhs/complete-guide-for-typescript-for-mongoose-for-node-js-8cc0a7e470c1)\n- [Strongly typed models with Mongoose and TypeScript](https://medium.com/@tomanagle/strongly-typed-models-with-mongoose-and-typescript-7bc2f7197722)\n\n# Usage\n\n\u003c!-- commands --\u003e\n\n## `mtgen \u003cMODEL_PATH]\u003e`\n\nGenerate a Typescript file containing Mongoose Schema typings.\n\n\u003e If you run into unknown type issues, [check your Mongoose version](#mongoose-version). For Mongoose v5.11+, ensure you have removed the deprecated community typings `@types/mongoose`.\n\n```\nUSAGE\n  $ mtgen \u003cMODEL_PATH\u003e\n\nOPTIONS\n  -c, --config=config     [default: ./] Path of `mtgen.config.json` or its root folder. CLI flag\n                          options will take precendence over settings in `mtgen.config.json`.\n\n  -d, --dry-run           Print output rather than writing to file.\n\n  -h, --help              Show CLI help\n\n  -i, --imports=imports   Custom import statements to add to the output file. Useful if you use\n                          third-party types in your mongoose schema definitions. For multiple imports,\n                          specify this flag more than once.\n\n  -o, --output=output     [default: ./src/interfaces] Path of output file to write generated typings.\n                          If a folder path is passed, the generator will create a `mongoose.gen.ts` file\n                          in the specified folder.\n\n  -p, --project=project   [default: ./] Path of `tsconfig.json` or its root folder.\n\n  --dates-as-strings      Dates will be typed as strings. Useful for types returned to a frontend by API requests.\n\n  --debug                 Print debug information if anything isn't working\n\n  --no-format             Disable formatting generated files with prettier.\n\n  --no-mongoose           Don't generate types that reference mongoose (i.e. documents). Replace ObjectId with\n                          string.\n\n  --no-populate-overload  Disable augmenting mongoose with Query.populate overloads (the overloads narrow\n                          the return type of populated documents queries).\n```\n\nSpecify the directory of your Mongoose schema definitions using `MODEL_PATH`. Defaults to `\"**/models/!(index).ts\"`\n\n_See code: [src/index.ts](https://github.com/francescov1/mongoose-tsgen/blob/master/src/index.ts)_\n\n\u003c!-- commandsstop --\u003e\n\n## Blob patterns and `package.json`\n\nWrap blob patterns with double quotes like so: `mtgen \"models/**/*.ts\"`.\n\nUse escape characters for wrapping blob patterns in `package.json`:\n\n```json\n\"scripts\": {\n  \"generate-mongoose-types\": \"mtgen \\\"models/**/*.ts\\\"\"\n}\n```\n\n\n## Configuration File\n\nAll CLI options can be provided using a `mtgen.config.json` file. Use the `--config` option to provide the folder path containing this file (\"./\" will be searched if no path is provided). CLI options will take precendence over options in the `mtgen.config.json` file.\n\n\u003e mtgen.config.json\n\n```json\n{\n  \"imports\": [\"import Stripe from \\\"stripe\\\"\"],\n  \"output\": \"./src/custom/path/mongoose-types.ts\"\n}\n```\n\n## Use as a module\n\n`mongoose-tsgen` can also be imported or required and used programmatically. Below is an example:\n\n```typescript\nimport MongooseTsgen from \"mongoose-tsgen\";\n\nasync function run() {\n    const tsgen = new MongooseTsgen();\n    await tsgen.generateDefinitions({\n        flags: {\n            \"dry-run\": false,\n            \"no-format\": false,\n            \"no-mongoose\": false,\n            \"no-populate-overload\": false,\n            \"dates-as-strings\": false,\n            debug: false,\n            output: \"./src/interfaces\",\n            project: \"./tsconfig.test.json\"\n        },\n        args: {\n            model_path: \"./src/helpers/tests/artifacts/**/*.ts\" // optional\n        }\n    });\n}\n\nrun()\n```\n\n## Query Population\n\nMongoose fields with a `ref` property will be typed as `RefDocument[\"_id\"] | RefDocument`. As part of the generated file, mongoose will be augmented with `Query.populate` overloads to narrow return types of populated queries (this can be disabled using the `--no-populate-overload` flag). A helper type `PopulatedDocument` and a type guard function `IsPopulated` will also be generated to help with handling populated documents, see usage below:\n\n```typescript\nimport { IsPopulated, PopulatedDocument } from \"../interfaces/mongoose.gen.ts\";\n\n// UserDocument[\"bestFriend\"] = mongoose.Types.ObjectId | UserDocument\nfunction unsafeType(user: UserDocument) {\n  // type guard\n  if (IsPopulated(user.bestFriend))) {\n    // user.bestFriend is confirmed to be populated, typescript will allow accessing its properties now\n    console.log(user.bestFriend._id)\n  }\n}\n\n// `user` is typed as a UserDocument with `bestFriend` populated\nfunction safeType(user: PopulatedDocument\u003cUserDocument, \"bestFriend\"\u003e) {\n  console.log(user.bestFriend._id)\n}\n\n// due to the `Query.populate` overload, `user` will be typed as `PopulatedDocument\u003cUserDocument, \"bestFriend\"\u003e`\n// rather than the usual `UserDocument`\nconst user = await User.findById(uid).populate(\"bestFriend\").exec()\n\n// completely type-safe\nsafeType(user)\n```\n\nBoth the mongoose `populate` overload and the `PopulateDocument` type handle nested and array types with ease; you rarely need to worry about enforcing types manually. In the case that the populated type cannot be determined, types will fallback to the generic `RefDocument[\"_id\"] | RefDocument`.\n\n# Example\n\n### ./src/models/user.ts\n\n```typescript\nimport mongoose, { Schema } from \"mongoose\";\nimport { UserDocument, UserModel, UserSchema, UserObject } from \"../interfaces/mongoose.gen.ts\";\n\n// UserSchema type\nconst UserSchema: UserSchema = new Schema({\n  email: {\n    type: String,\n    required: true\n  },\n  firstName: {\n    type: String,\n    required: true\n  },\n  lastName: {\n    type: String,\n    required: true\n  },\n  metadata: Schema.Types.Mixed,\n  bestFriend: {\n    type: Schema.Types.ObjectId,\n    ref: \"User\"\n  },\n  friends: [\n    {\n      uid: {\n        type: Schema.Types.ObjectId,\n        ref: \"User\",\n        required: true\n      },\n      nickname: String\n    }\n  ],\n  city: {\n    coordinates: {\n      type: [Number]\n    }\n  }\n});\n\n// NOTE: `this: UserDocument` is required for virtual properties to tell TS the type of `this` value using the \"fake this\" feature\n// you will need to add these in after your first ever run of the CLI\nUserSchema.virtual(\"name\").get(function (this: UserDocument) {\n  return `${this.firstName} ${this.lastName}`;\n});\n\nUserSchema.methods = {\n  isMetadataString() {\n    return this.metadata === \"string\";\n  }\n};\n\nUserSchema.statics = {\n  async getFriends(friendUids: UserDocument[\"_id\"][]): Promise\u003cUserObject[]\u003e {\n    return await this.aggregate([{ $match: { _id: { $in: friendUids } } }]);\n  }\n};\n\nUserSchema.query = {\n  populateFriends() {\n    return this.populate(\"bestFriend\", \"firstName lastName\");\n  }\n};\n\nexport const User = mongoose.model\u003cUserDocument, UserModel\u003e(\"User\", UserSchema);\n```\n\n### generate typings\n\n```bash\n# run mongoose-tsgen\nnpx mtgen\n```\n\n### generated typings file ./src/interfaces/mongoose.gen.ts\n\n```typescript\nimport mongoose from \"mongoose\";\n\nexport type UserFriend = {\n  uid: User[\"_id\"] | User;\n  nickname?: string;\n  _id: mongoose.Types.ObjectId;\n}\n\nexport type UserObject = User;\n\nexport type UserQueries = {\n  populateFriends: () =\u003e mongoose.Query\u003cany, UserDocument, UserQueries\u003e \u0026 UserQueries;\n}\n\nexport type UserMethods = {\n  isMetadataString: (this: UserDocument) =\u003e boolean;\n}\n\nexport type UserStatics = {\n  getFriends: (this: UserModel, friendUids: UserDocument[\"_id\"][]) =\u003e Promise\u003cUserObject[]\u003e;\n}\n\nexport type UserModel = mongoose.Model\u003cUserDocument, UserQueries\u003e \u0026 UserStatics\n\nexport type UserSchema = mongoose.Schema\u003cUserDocument, UserModel, UserMethods, UserQueries\u003e\n\nexport type User = {\n  email: string;\n  firstName: string;\n  lastName: string;\n  bestFriend?: User[\"_id\"] | User;\n  friends: UserFriend[];\n  city: {\n    coordinates: number[];\n  };\n  _id: mongoose.Types.ObjectId;\n}\n\nexport type UserFriendDocument = mongoose.Types.Subdocument \u0026 {\n  uid: UserDocument[\"_id\"] | UserDocument;\n  nickname?: string;\n  _id: mongoose.Types.ObjectId;\n};\n\nexport type UserDocument = mongoose.Document\u003cmongoose.Types.ObjectId, UserQueries\u003e \u0026\n  UserMethods \u0026 {\n    email: string;\n    firstName: string;\n    lastName: string;\n    metadata?: any;\n    bestFriend?: UserDocument[\"_id\"] | UserDocument;\n    friends: mongoose.Types.DocumentArray\u003cUserFriendDocument\u003e;\n    city: {\n      coordinates: mongoose.Types.Array\u003cnumber\u003e;\n    };\n    name: string;\n    _id: mongoose.Types.ObjectId;\n  };\n```\n\n## Known Issues\n\n### Type instantiation is excessively deep and possibly infinite\n\nThis issue is present when using **Mongoose v6.3.2 - v6.4.0** due to a conflict in types.\n\nWorkarounds:\n- Fix your Mongoose version to `\u003c6.3.2` or `\u003e6.4.0`.\n- Use the `--no-populate-overload` flag.\n\nReferences:\n- https://github.com/Automattic/mongoose/issues/11787\n- https://github.com/francescov1/mongoose-tsgen/issues/95\n\n## Development\n\n- [ ] Consider [population field selection](https://mongoosejs.com/docs/populate.html#field-selection) when typing populates\n- [ ] Slim down dependencies: `oclif` is unnecessarily large, `prettier` should be handled by users if desired.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancescov1%2Fmongoose-tsgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrancescov1%2Fmongoose-tsgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrancescov1%2Fmongoose-tsgen/lists"}