-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
[Typscript] Wrong type for new Model(doc)
#10302
Comments
const Kitten = mongoose.model('Kitten', kittenSchema); Is this line added correctly in your code ? |
yes it is, it's the line hidden by Vscode popup |
to this |
same |
@Zenthae one more thing make sure your |
still the same issue |
can you share on codepen ? |
Make sure you're running Mongoose >= 5.12.6, we changed this type definition with #10074 so either you're using an older version of Mongoose or VSCode is picking up the wrong version of Mongoose type definitions. |
i'm using mongoose .....
interface Model<T, TQueryHelpers = {}, TMethods = {}> extends NodeJS.EventEmitter, AcceptsDiscriminator {
new(doc?: T | any): EnforceDocument<T, TMethods>;
..... but it's still not working, the inferred type is here is my model interface UserModel extends IUser, Document {
comparePassword(plainPassword: string): boolean;
}
export const userSchema = new Schema<UserModel>({
username: { type: String, unique: true },
password: String,
});
userSchema.pre('save', function (this: UserModel, next) {
if (!this.isModified('password')) return next();
this.password = hashSync(this.password, 15);
next();
});
userSchema.method('comparePassword', function (this: UserModel, plainPassword: string) {
return compareSync(plainPassword, this.password);
});
export const User = model<UserModel>('User', userSchema);
const u = new User({}); i tested using this too, and it's still inferring |
We should see if: new(doc?: T): EnforceDocument<T, TMethods>;
new(doc?: any): EnforceDocument<T, TMethods>; helps, re: #10343 |
We took a look and unfortunately the suggestion in #10302 (comment) doesn't really help. TypeScript just always falls back to interface User {
name: string;
id: number;
}
const UserModel = model<User>('User', new Schema({ name: String, id: Number }));
const doc = new UserModel({ name: 'test' } as User); An alternative that we'll consider for the future is making new(doc?: T | any): EnforceDocument<T, TMethods>;
(doc?: T): EnforceDocument<T, TMethods>; Another potential alternative would be creating a separate static function, like |
i think that the |
I think there should be a way to enforce object creation that matches the schema.
Not to mention that adding "as User" everywhere is not practical. |
Is there a reason why someone would not want it to be strongly typed? This is kinda a bummer since AFAIK we had strongly typed constructor params and create function until mongoose started providing its own types and
It'll also happily cast unknown types to whatever they need to be because you're not telling ts to ensure that it's User. You're telling ts that this certainly is an User and ts will only complain if it can be certain that you're wrong. |
@FINDarkside "Is there a reason why someone would not want it to be strongly typed?" <-- Yes, if you want to pass in |
It'd still work if |
I'm not sure about your reasoning here @vkarpov15. This is a confusing reason to default to From a user of Typescript perspective, I'd want 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. |
This is exactly what I'd expect to be getting from Mongoose when using Typescript (and I think most people would agree). Does anybody know if there is progress being made on this? |
is this still a issue with mongoose 6.6.1? currently Line 124 in 69c99d2
|
@hasezoey oddly enough, I think this behavior is still there. I don't think this behavior is an issue though. For example, the following script compiles fine. import mongoose from 'mongoose';
const schema = new mongoose.Schema<{ name?: string }>({ name: String });
const Test = mongoose.model<{ name?: string }>('Test', schema);
const doc = new Test({ name: 42, other: 'bar' }); And VS Code autocomplete thinks that I genuinely am not sure why. |
well in this case it is because the parameter TL;DR: the type for parameter generic Line 119 in ff7eed5
generic Line 124 in ff7eed5
so basically, i answered my own question:
yes it is still a issue in mongoose 6.6.3 |
Hi there, I just entered mongoose world and I want it to use in my TypeScript project . So far the setup was okay... but I found out same issue as @hasezoey is talking about in his latest message. Wrong mongoose type definition in new <DocType = T>(doc?: DocType, fields?: any | null, options?: boolean | AnyObject): HydratedDocument<T, TMethodsAndOverrides, IfEquals<TVirtuals, {}, ObtainSchemaGeneric<TSchema, 'TVirtuals'>, TVirtuals>> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>; produces incorrect behavior when creating new instance of a model When I fix it to new (doc?: T, fields?: any | null, options?: boolean | AnyObject): HydratedDocument<T, TMethodsAndOverrides, IfEquals<TVirtuals, {}, ObtainSchemaGeneric<TSchema, 'TVirtuals'>, TVirtuals>> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>; Then I'm getting the correct TypeScript error: If needed, I can contribute to help to solve this issue ASAP. 🙂 |
the change you have made would conflict with other things mongoose supports, at least from what i can tell: because before a the proper thing for this issue is to bind |
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'>; |
i dont think it is a good way to use |
@FilipPyrek how exactly is your suggested approach different from what is already there? The |
That suggested solution doesn't create a schema breaking change. The problem is that In the suggested solution you can choose if you want the original "broken" approach or if you want |
#13038 fixes this for edit: reading through this thread, I guess it's similar to what @FilipPyrek has been suggesting. So the question becomes: would you be willing to put this change in Mongoose 7 so Typescript users can have strict types by default? |
This is still an issue with v8 of mongoose even when following the examples from the docs. Running the below lines infers the results on each to be of type const user1 = await User.findOne({}).exec();
// where params is an object that represents the valid fields defined on the user schema
const user2 = new User({...params}); Edit: Nevermind, this was resolved by upgrading my typescript from 3.9.9 -> 5.X |
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 thesave()
it. the type ofdoc
is alwaysany
which break the auto-completion for properties added by the user model.If the current behavior is a bug, please provide the steps to reproduce.
Quick Start example from the website
tsconfig.json
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
The text was updated successfully, but these errors were encountered: