-
-
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
How do you get type checking for schema definitions to work when using Model.create or other Model methods? #11148
Comments
Yes surprisingly this is the definition for the /** Creates a new document or documents */
create(docs: (AnyKeys<T> | AnyObject)[], options?: SaveOptions): Promise<HydratedDocument<T, TMethods, TVirtuals>[]>;
create(docs: (AnyKeys<T> | AnyObject)[], callback: Callback<HydratedDocument<T, TMethods, TVirtuals>[]>): void;
create(doc: AnyKeys<T> | AnyObject): Promise<HydratedDocument<T, TMethods, TVirtuals>>;
create(doc: AnyKeys<T> | AnyObject, callback: Callback<HydratedDocument<T, TMethods, TVirtuals>>): void;
create<DocContents = AnyKeys<T>>(docs: DocContents[], options?: SaveOptions): Promise<HydratedDocument<T, TMethods, TVirtuals>[]>;
create<DocContents = AnyKeys<T>>(docs: DocContents[], callback: Callback<HydratedDocument<T, TMethods, TVirtuals>[]>): void;
create<DocContents = AnyKeys<T>>(doc: DocContents): Promise<HydratedDocument<T, TMethods, TVirtuals>>;
create<DocContents = AnyKeys<T>>(...docs: DocContents[]): Promise<HydratedDocument<T, TMethods, TVirtuals>[]>;
create<DocContents = AnyKeys<T>>(doc: DocContents, callback: Callback<HydratedDocument<T, TMethods, TVirtuals>>): void; I'm sure there is a reasoning behind allowing any document through but I'm not sure I grasp it. Isn't the role of typescript to prevent objects not conforming to the type definition to not be instantiated thus saved to the database ? |
Unfortunately this is expected behavior for several reasons. Also, your |
@vkarpov15 thanks for reaching out!
I totally get that
This works, however on small downside is that you lose type suggestions/Intellisense. IIRC before submitting this issue on github I tried this syntax but I thought I must be doing something wrong and I couldn't find more info about it online. const createUser = async () => {
await User.create<IUser>({ name: 'bar', age: 50 }); // ✅ valid
await User.create<IUser>({ name: 'bar' }); // ❌ missing key
await User.create<IUser>({ age: 50 }); // ❌ missing key
await User.create<IUser>({ name: false, age: 50 }); // ❌ wrong type
await User.create<IUser>({ name: 'bar', age: 50, test: 123 }); // ❌ arbitrary key
}; The code above works as expected (with the few downsides I mentioned) and typescript correctly tells if there are missing keys, wrong types or arbitrary properties. I guess it's not totally ideal (for me personally) but if provides type checking then it's good enough. I have one quick question, is there a way or specific syntax which would let me achieve the same or similar behavior, but when creating a |
It's very strange that intellisense doesn't pick up that Re |
Slightly off-topic, but allow me to point out that other Model methods that involve an update object, but don't accept a generic type parameter are also producing mixed results (in terms of type checking and intellisense). const createUser = async () => {
await User.findByIdAndUpdate('123', { valid: false });
await User.findOneAndUpdate({ name: 'foo' }, { valid: false });
await User.findOneAndReplace({ name: 'foo' }, { valid: false, }); // ✅ intellisense (suggestions)
await User.replaceOne({ name: 'foo' }, { valid: false }) // ✅ intellisense (suggestions)
await User.updateMany({ name: 'foo' }, { valid: false })
await User.updateOne({ name: 'foo' }, { valid: false })
}; All of these are considered valid by TS/Mongoose, while obviously they are not. I just wanted to put these examples out there in case you want to look into them, but I totally understand that implementing/improving this might not be a priority (or a planned feature) at this point of time.
That would be awesome, thank you and looking forward to try it out, cheers! |
|
@vkarpov15 What is the reasoning behind this? When would I ever want to perform an update with properties that are not in the schema? Isn't this exactly why we would want TypeScript in the first place? |
I have found somewhat of a workaround. I just extend my Mongoose Model with another class const testSchema = new Schema({
name: { type: String, required: true },
});
const TestModel = model("Test", testSchema);
class Test extends TestModel {}
const myTest = new Test({ name: 123 }); // gives typescript error
const myOtherTest = new Test({ name: '123' }); // no errors, as expected Don't know why it works. Don't know if there are any implications on using the methods on the Model. I thought it might help you guys. Try it out |
Do you want to request a feature or report a bug?
I have a question.
What is the current behavior?
Hello. I have been using Mongoose for years, and recently I started with Typescript so currently in the process of converting, and I have a couple of quick questions. Let's say I have a very simple schema, nearly identical as the one provided in the TypeScript Support section of Mongoose docs.
What is the expected behavior?
What I want to be able to have is a type checking against the schema definition, whenever I use methods such as
Model.create
or when I create a new instance of theUser
model. Here for example, I expect Typescript to complain (but it doesn't):In this example, it lets me use completely arbitrary object properties, while also letting me omit
name
andage
keys as defined in byIUser
interface inUserSchema
andUser
model. As far as Typescript is concerned, all of this code is valid and no errors are detected. I can slightly improve this if I force theIUser
interface when creating the document, however, as you can see this only solves half of the problem.In VSCode, if I hover with my mouse over
Schema
where I am defining it, it lets me see how the definition works, and that tells me that all the object properties are set as optional and not respecting theIUser
interface where in fact they are required:But my knowledge in TypeScript is not good enough to understand why this is happening or if it's necessary.
Surprisingly, I was able to find very little on this topic online, closest one is this question on StackOverflow from 2 months ago, but it has no answers.
So overall my question is, how do I achieve type checking using model methods, is it even possible, and if it is, what is the correct way to do it? I apologize in advance in case I am missing something obvious here, as I mentioned was only starting with TS and TS Mongoose so there is a possibility that I am doing something incorrectly. Nevertheless, any guidance or quick example would be highly appreciated. Cheers!
What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Node.js 16.13.1
Mongoose 6.1.3
VSCode 1.63.2
tsconfig.json
The text was updated successfully, but these errors were encountered: