UpdateQuery generic type makes no sense on a schema with virtual getter and setter
See original GitHub issueDo you want to request a feature or report a bug? bug
What is the current behavior? UpdateQuery requires a Document interface generic but this doesn’t work when your document has a virtual with getter and setter. If a virtual has both getter and setter I want to only allow the user to update either the get properties or the set property but the required document interface includes both.
If the current behavior is a bug, please provide the steps to reproduce.
// sample.model.ts
import mongoose from "mongoose"
export interface SampleInput {
name: {
firstName: string,
lastName: string
} | {
fullName: string
}
}
export interface SampleDoc extends SampleInput, mongoose.Document {
name: { firstName: string, lastName: string, fullName: string }
}
const SampleSchema = new mongoose.Schema<SampleDoc>({
name: {
firstName: { type: String, required: true },
lastName: { type: String, required: true }
}
}
SampleSchema.virtual("name.fullName")
.get(function (this: SampleDoc) { return this.name.firstName + " " + this.name.lastName })
.set(function (this: SampleInput, fullName: string) {
this.name = {
firstName: fullName.split(" ")[0],
lastName: fullName.split(" ")[1]
}
})
export const Sample = mongoose.model<SampleDoc>("Sample", SampleSchema)
// sample.service.ts
import { SampleInput, Sample } from "sample.model"
export const update = async (id: string, doc: SampleInput /* or UpdateQuery<SampleInput> */) => {
// findByIdAndUpdate requires doc to be of type SampleDoc (or UpdateQuery<SampleDoc>) but that makes no sense
// because SampleDoc requires all 3 name properties even though that would interfere with the virtual setter
// hence why I want it to be SampleInput instead
return await Sample.findByIdAndUpdate(id, doc).exec()
}
/* Error:
await Sample.findByIdAndUpdate(id, doc).exec()
^^^
No overload matches this call.
The last overload gave the following error.
Argument of type 'SampleInput' is not assignable to parameter of type 'UpdateWithAggregationPipeline | UpdateQuery<SampleDoc> | undefined'.
Type 'SampleInput' is not assignable to type 'UpdateQuery<SampleDoc>'.
Type 'SampleInput' is not assignable to type 'ReadonlyPartial<_AllowStringsForIds<LeanDocument<SampleDoc>>>'.
Types of property 'name' are incompatible.
Type '{firstName: string, lastName: string} | {fullName: string}' is not assignable to type '({firstName: string, lastName: string, fullName: string}) | undefined'.
Type '{firstName: string, lastName: string}' is not assignable to type '{firstName: string, lastName: string, fullName: string}'.
Property 'fullName' is missing in type '{firstName: string, lastName: string}' but required in type '{firstName: string, lastName: string, fullName: string}'. [ts(2769)]
*/
// tsconfig.json
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "Node",
"lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
"esModuleInterop": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"noEmit": true,
"experimentalDecorators": true,
"baseUrl": ".",
"types": ["@types/node"]
},
"exclude": ["node_modules", "dist"]
}
What is the expected behavior? UpdateQuery integrates getters and setters in its generic type so it doesn’t allow for both to be set at the same time.
What are the versions of Node.js, Mongoose and MongoDB you are using? Note that “latest” is not a version. node v14.16.1 mongoose 5.13.3 mongodb 5.0.1
Issue Analytics
- State:
- Created 2 years ago
- Comments:6
@DaDoBaag https://mongoosejs.com/docs/migrating_to_6.html#typescript-changes
Our TypeScript docs don’t recommend passing in an object that extends
Document
toSchema
andModel
. The spirit ofDocType
is that it should represent what your document looks like in the database. No virtuals, methods, etc.We unfortunately don’t have an ideal solution for virtuals right now, but the workaround is to pass a separate interface containing virtuals as the
TInstanceMethods
generic as shown below.In v6.0.7 we’re adding a
TVirtuals
to theModel
interface so you’ll be able to do: