mongoose: [Typscript] Wrong type for `new Model(doc)`

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

bug

What is the current behavior?

When using new Model(doc) to create a new model and the save() it. the type of doc is always any which break the auto-completion for properties added by the user model.

image

If the current behavior is a bug, please provide the steps to reproduce.

Quick Start example from the website

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "types": ["mongoose"],
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "exclude": ["node_modules"],
  "include": ["src/**/*.ts"]
}

What is the expected behavior?

instead of having any it should use the provided type.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that “latest” is not a version.

nodejs: v16.1.0 mongoose: 5.12.10

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 1
  • Comments: 28 (1 by maintainers)

Commits related to this issue

Most upvoted comments

And VS Code autocomplete thinks that DocType is {} ? I genuinely am not sure why.

well in this case it is because the parameter doc uses the function generic DocType, which is defaulted to a unbound T generic in Model, and because it is a “creating method” (how i call it), it uses the value it finds as that generic

TL;DR: the type for parameter doc is unbound, so it uses the value it has, which is {}

generic T: https://github.com/Automattic/mongoose/blob/ff7eed50ead64d209b9d33a6b4fff58d41d7c3b1/types/models.d.ts#L119

generic DocType (and the whole function declaration): https://github.com/Automattic/mongoose/blob/ff7eed50ead64d209b9d33a6b4fff58d41d7c3b1/types/models.d.ts#L124


so basically, i answered my own question:

is this still a issue with mongoose 6.6.1?

yes it is still a issue in mongoose 6.6.3

@FINDarkside “Is there a reason why someone would not want it to be strongly typed?” <-- Yes, if you want to pass in req.body or some other arbitrary object.

I’m not sure about your reasoning here @vkarpov15. This is a confusing reason to default to any.

From a user of Typescript perspective, I’d want new MyModel to expect input parameters as defined in the interface I had explicitly associated with the model.

While there may well be users that want to pass in req.body or an arbitrary object, I’d argue that they should be the ones to explicitly code in that intention.

Well, that’s quite unfortunate because it breaks Developer Experience when trying to ensure type safety with TypeScript.

Maybe it could be done via conditional generic parameters like this for example:

// just a quick illustration of the idea

 new <DocType = T>(doc?: DocType extends 'full' ? T : DocType, fields?: any | null, options?: boolean | AnyObject): HydratedDocument<T, TMethodsAndOverrides, IfEquals<TVirtuals, {}, ObtainSchemaGeneric<TSchema, 'TVirtuals'>, TVirtuals>> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
image

@FINDarkside “Is there a reason why someone would not want it to be strongly typed?” <-- Yes, if you want to pass in req.body or some other arbitrary object.