Closed pauIbanez closed 6 months ago
I have to add here that to reproduce this error you need to load the a model with this schema and then actually load the model somewhere in a program, even if you don't call it in runtime.
From some more experimentation I've also encountered that all of these cases can fail as well, but I have no idea what makes them fail in some test and others they pass normally:
interface Test {
information: {
name: boolean; // <- Note this is a boolean in the type
};
};
const schema = new Schema<Test>({
information: {
_id: false,
name: {
type: String,
required: true,
},
},
})
or:
interface Test {
information: {
name: string;
};
};
const schema = new Schema<Test>({
information: {
_id: false,
name: {
type: Boolean, // <- Note this is a boolean in the schema
required: true,
},
},
})
as well as having a property defined in ether schema or interface that the other does not have
import * as mongoose from 'mongoose';
interface Test {
information: {
isBug: boolean;
}
}
const testSchema = new mongoose.Schema<Test>({
information: {
_id: false,
isBug: {
type: Boolean,
required: true
}
}
});
const TestModel = mongoose.model<Test>('Test', testSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
await TestModel.create({ information: { isBug: true } });
}
run();
After experimenting some more it seems that inferring the type in a schema overall does not work as expected. I've mainly had the Boolean issue, but it turns out that for some other types gives similar issues.
I've found that if you use the property enum in any of the fields it also breaks the compiler:
import * as mongoose from 'mongoose';
enum TestEnum{
hello = "hi",
bye = "good ridance"
}
interface Test {
information: {
isBug: TestEnum;
}
}
const testSchema = new mongoose.Schema<Test>({
information: {
_id: false,
isBug: {
type: String,
required: true,
enum: TestEnum
}
}
});
const TestModel = mongoose.model<Test>('Test', testSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
await TestModel.create({ information: { isBug: true } });
}
run();
In some other cases, the compiler fails in an even more unexpected way, but I've sadly not been able to reproduce. I had a this setup (as a workaround):
import * as mongoose from 'mongoose';
enum TestEnum{
hello = "hi",
bye = "good ridance"
}
interface Test {
information: {
isBug: TestEnum;
}
}
const testSchema = new mongoose.Schema<Test>({
information: {
_id: false,
type: {
isBug: {
type: String,
required: true,
enum: TestEnum
}
}
}
});
const TestModel = mongoose.model<Test>('Test', testSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
await TestModel.create({ information: { isBug: true } });
}
run();
And I got a similar issue basically telling me that "information" did not have a property called type.
My best guess as to why this happens is that when mongoose converts the types:
{ isBug?: SchemaDefinitionProperty<boolean>;}
it does not add the property _id
as to WHY this happens, the only real connection between the failing properties and the _id property that I could find is that they are both boolean, but as I just explained here enums fail aswell so I'm not so sure this is the case anymore.
Are you able to upgrade to TypeScript 5.2? I can confirm that the following scripts fail in TypeScript 5.1.6, but compile fine in TypeScript 5.2.
import * as mongoose from 'mongoose';
interface Test {
information: {
isBug: boolean;
}
}
const testSchema = new mongoose.Schema<Test>({
information: {
_id: false,
isBug: {
type: Boolean,
required: true
}
}
});
const TestModel = mongoose.model<Test>('Test', testSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
await TestModel.create({ information: { isBug: true } });
}
run();
import * as mongoose from 'mongoose';
enum TestEnum{
hello = "hi",
bye = "good ridance"
}
interface Test {
information: {
isBug: TestEnum;
}
}
const testSchema = new mongoose.Schema<Test>({
information: {
_id: false,
isBug: {
type: String,
required: true,
enum: TestEnum
}
}
});
const TestModel = mongoose.model<Test>('Test', testSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
await TestModel.create({ information: { isBug: true } });
}
run();
Also, it is worth mentioning that, in the contexts you mentioned, _id: false
doesn't do anything. For example, in the following, _id: false
is unnecessary because information
is a nested path, not a subdocument. Subdocuments get _id
by default (like top-level documents), nested paths do not.
const schema = new Schema<Test>({
information: {
_id: false, // <-- can remove this, no change in runtime behavior
isBug: Boolean,
},
})
In general, we advise against using _id: false
in your schema definition, in favor of passing _id: false
as a schema option. _id: false
in schema definition is more of an unexpected quirk that we've maintained because it became too prevalent for us to disable without causing a lot of headache.
Thank you for your information, I’ll update my typescript and give it a try.
However i don’t know about the _id thing. I’ll also try removing it, but from my experience sub paths generate id automatically if I don’t put that in there. Usually I do pass the _id false as a schema option when liking types to schemas, but as I said I’ve found that mested paths do generate ids when i don’t specify that _id:false.
I’ll try out both things and get back to you!
This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days
This issue was closed because it has been inactive for 19 days and has been marked as stale.
Prerequisites
Mongoose version
7.3.1
Node.js version
v16.14.0
MongoDB server version
5.6.0
Typescript version (if applicable)
5.1.6
Description
When creating a typed mongoose schema, if a property in a sub-object is of type Boolean and the syntax is "extended":
instead of:
The compiler will fail with the following error:
further down:
What's weird about it is the following, normally the
_id: false
is allowed to be sharing a space with the objectinformation
properties as long as no other "declarations" are done. If I want to say define a defaultinformation
I would have to use something like:The problem bug or at least very sus activity comes from this. ANY type other than Boolean is accepted directly, the only one that fails (That I know) is boolean. See the steps to reproduce for more info, as there I expand on this.
Steps to Reproduce
The issue arises when you have a structure like this:
While if you have the same with, say, a string, it does work as expected and compiles normally:
If you have it in "conditional" syntax it will also compile normally:
Any non-defined or non-equal type will also not cause an error, so something like:
or:
Expected Behavior
I'd expect all the types to act the same and ether be accepted with the _id: false parameter in the object or not, but seems like Boolean is the only exception that I've found.
I want to also note a very easy workaround to this, which is to use the
type
property:But the fact that this can be solved this way does not excuse the issue.
I hope I explained myself