francescov1 / mongoose-tsgen

A plug-n-play Typescript generator for Mongoose.
103 stars 24 forks source link

Don't duplicate types for sub documents used in multiple places #57

Closed Narretz closed 3 years ago

Narretz commented 3 years ago

If you use the same subDocument in multiple fields, mongoose-tsgen generates a type for each field, even though the underlying type is the same. This makes it a bit tricky to import the Document type needed to type the invocation of mongoose.model().

Example:

project schema:

import ProjectUser from './subDocuments/projectUser';

export const projectSchema: ProjectSchema = new Schema({
    goodUsers: {
      type: [ProjectUser.schema],
      default: [],
    },
    badUsers: {
      type: [ProjectUser.schema],
      default: [],
    },
})

projectUser schema:

import mongoose, { Schema } from 'mongoose';
// ProjectUserDocument doesn't exist, instead we have ProjectGoodUserDocument and ProjectBadUserDocument
import { ProjectUserDocument } from '../../interfaces/mongoose.gen';

// schema def ...

export default mongoose.model<ProjectUserDocument>('ProjectUserDocument', schema);

Is it possible to detect that a sub Document is used multiple times and generate a base type? The name of the base type could be derived from the file name if it is defined in an external file, or from the variable name if it is defined in the same file.

francescov1 commented 3 years ago

Hey @Narretz

This is actually already possible (if I understand correctly)! As long as your projectUser file exports a schema and is in the model path passed to mtgen, it should have a type generated called ProjectUserDocument, as well as the individual types GoodUserProjectUserDocument and BadUserProjectUserDocument.

Use the specific types anytime you are accessing the values from the parent document (project) because they will have the additional embedded document methods attached (ie GoodUserProjectUserDocument.parent()).

If something isn't working right, let me know how your project is setup and I can better help!

Narretz commented 3 years ago

Hi @francescov1, thanks for the quick response, I will investigate this further and provide a repro

francescov1 commented 3 years ago

Hey @Narretz, checking in if you've had the chance to investigate further? Looking to close this soon since the feature should be supported

Narretz commented 3 years ago

Hi @francescov1 I took another look, and I think what I missed initially was to include the subDocument in the model path. However, it still feels confusing to have these types:

export type Project= {
  _id: mongoose.Types.ObjectId;
  updatedAt?: Date;
  createdAt?: Date;
  knownUsers: ProjectUnknownUser[];
  unknownUsers: ProjectUnknownUser[];
};

Both knownUsers and unknownUsers have the same type shape, yet the final type for project only uses ProjectUnknownUser. I guess what I would like is that this type somehow gets a "common" name. But it definitely works as is.

francescov1 commented 3 years ago

Sounds good, the generator logic is a bit overcomplicated so I want to spend some time cleaning it up before addressing more niche features like this.

Closing this for now, but if this becomes an issue or you'd like to see it in the future feel free to re-open!