Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper setup for instance methods with Typescript #11682

Closed
ShaneKeney opened this issue Apr 18, 2022 · 7 comments
Closed

Proper setup for instance methods with Typescript #11682

ShaneKeney opened this issue Apr 18, 2022 · 7 comments
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Milestone

Comments

@ShaneKeney
Copy link

Do you want to request a feature or report a bug?
Help.

What is the current behavior?
Following is specified in mongoose documentation: "We recommend your document interface contain the properties defined in your schema and line up with what your documents look like in MongoDB. Although you can add instance methods to your document interface, we do not recommend doing so."

What is the recommended way for proper compatibility with Typescript project if extends Document is also discouraged. This is specifically being asked in reference to instance methods such that TS can check properly when such methods are being used elsewhere in the project.

What is the expected behavior?

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Version of "mongoose": "^6.0.12",

@IslandRhythms IslandRhythms added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Apr 19, 2022
@Uzlopak
Copy link
Collaborator

Uzlopak commented Apr 26, 2022

The reason why it is not recommended, is because the typescript engine in vscode could get very slow. If you have no issue with that, you can ofc extend from Document. Maybe we should document that better to know why we dont recommend to extend from Document. Or maybe fix the underlying performance issue.

@ShaneKeney
Copy link
Author

@Uzlopak Understood. That definitely makes me feel more at ease for leveraging it in our project. This is by no means insinuating timeline or urgency because you all do great work and have bigger ticket items to consider.

I think a lot of confusion with TS and Mongoose overall can be solved with more concrete examples of how to set up a boiler plate project via common use cases.
e.g. Model.create does not check field types or give any TS safety
e.g. Schema's that use type: String, required: true, default: "Hello" for supplying default values are confusing to deal with when creating the related TS interface.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Apr 26, 2022

@mohammad0-0ahmad is currently working on more typesafety.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Apr 26, 2022

#11563

@vkarpov15 vkarpov15 added this to the 6.3.3 milestone May 3, 2022
@vkarpov15 vkarpov15 added docs This issue is due to a mistake or omission in the mongoosejs.com documentation and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary labels May 3, 2022
@vkarpov15
Copy link
Collaborator

We're adding more info on this to our docs. Below is an example of how you can define instance methods in a type safe way.

import { Model, Schema, model } from 'mongoose';

interface IUser {
  firstName: string;
  lastName: string;
}

// Put all user instance methods in this interface:
interface IUserMethods {
  fullName(): string;
}

// Create a new Model type that knows about IUserMethods...
type UserModel = Model<IUser, {}, IUserMethods>;

// And a schema that knows about IUserMethods
const schema = new Schema<IUser, UserModel, IUserMethods>({
  firstName: { type: String, required: true },
  lastName: { type: String, required: true }
});
schema.method('fullName', function fullName() {
  return this.firstName + ' ' + this.lastName;
});

const User = model<IUser, UserModel>('User', schema);

const user = new User({ firstName: 'Jean-Luc', lastName: 'Picard' });
const fullName: string = user.fullName(); // 'Jean-Luc Picard'

lchenay added a commit to lchenay/mongoose that referenced this issue May 25, 2022
Uzlopak added a commit that referenced this issue May 25, 2022
Fix a broken link introduced by #11682
@ArnieGA
Copy link

ArnieGA commented Jul 14, 2022

@vkarpov15 Thank you!
However, even though your approach allows me to access the document's _id and the save method, intellisense inside the method is lost (everything is assumed as type any).

I mitigated this with:

schema.method('fullName', function (this: HydratedDocument<IUser>){
    (...)
});

...which gave me back intellisense. Is that approach accurate and acceptable? If not, could you please offer an alternative?
Thank you for your time

@vkarpov15
Copy link
Collaborator

@ArnieGA that approach is fine. Another alternative would be defining methods like this:

new Schema({ ... }, {
  methods: {
    fullName: function() { ... }
  }
});

which may work better with intellisense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Projects
None yet
Development

No branches or pull requests

5 participants