How do you get type checking for schema definitions to work when using Model.create or other Model methods?
See original GitHub issueDo 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.
import { model, Schema } from 'mongoose';
interface IUser {
name: string;
age: number;
}
const UserSchema = new Schema<IUser>({
name: { type: String, required: true },
age: { type: Number, required: true },
});
const User = model<IUser>('User', UserSchema);
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 the User
model. Here for example, I expect Typescript to complain (but it doesn’t):
const createUser = async () => {
const user = new User({ foo: 'bar' });
await User.create({ foo: 'bar' });
// or even
const user2 = new User({ name: false, age: 'invalid' });
};
In this example, it lets me use completely arbitrary object properties, while also letting me omit name
and age
keys as defined in by IUser
interface in UserSchema
and User
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 the IUser
interface when creating the document, however, as you can see this only solves half of the problem.
const createUser = async () => {
await User.create(<IUser>{ foo: 'bar' }); // works as intended, problem is detected (wavy red line)
await User.create(<IUser>{}); // not working, empty object
await User.create(<IUser>{ name: 'bar' }); // not working, "age" property is missing
await User.create(<IUser>{ age: 30 }); // not working, "name" property is missing
};
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 the IUser
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
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./out",
"strict": true,
"forceConsistentCasingInFileNames": true,
"preserveWatchOutput": true,
"esModuleInterop": true,
/* ESBuild specific config */
"noEmit": true,
"watch": true
},
"exclude": [
"**/node_modules",
"**/.*/",
"src/assets/**",
],
"include": [
"src"
]
}
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:7
It’s very strange that intellisense doesn’t pick up that
User.create<IUser>()
takesIUser
as a param. If that’s the case, I’m not sure what else we can do to support intellisense.Re
new User<IUser>({...})
, we don’t currently support that, but I just added that and we’ll release that in v6.1.6@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?