findByIdAndUpdate() type error
See original GitHub issueDo you want to request a feature or report a bug? bug
What is the current behavior? There seems to be a type error when using the interface pattern described here: Complete guide for Typescript with Mongoose for Node.js
No overload matches this call.
The last overload gave the following error.
Argument of type 'IProduct' is not assignable to parameter of type 'UpdateQuery<IProductDoc>'.
Type 'IProduct' is not assignable to type 'ReadonlyPartial<_UpdateQueryDef<LeanDocument<IProductDoc>>>'.
Types of property 'brand' are incompatible.
Type 'Record<string, any> | ObjectId' is not assignable to type 'string | ObjectId | undefined'.
Type 'Record<string, any>' is not assignable to type 'string | ObjectId | undefined'.
Type 'Record<string, any>' is not assignable to type 'string'. ts(2769)
index.d.ts(972, 5): The last overload is declared here.
If the current behavior is a bug, please provide the steps to reproduce.
Here’s how I actually implemented it:
// Custom mongoose base document
export interface IMongooseBaseDoc {
_id: Types.ObjectId;
createdAt?: Date;
updatedAt?: Date;
}
export interface IProduct {
brand: Types.ObjectId | Record<string, any>; //? Need fix
// ...
}
export interface IProductDoc extends IProduct, IMongooseBaseDoc {
images: Types.Array<IImage>;
brand: IBrandDoc["_id"]; // another model
}
export interface IProductPopulatedDoc extends IProductDoc {
brand: IBrandDoc; // this is why it needs to be `Record<string, any>` or typescript will complain
}
export type TSchema<T> = Record<
keyof T,
SchemaTypeOptions<any> | Schema | SchemaType
>
// ...
const ProductSchema = new Schema<TSchema<IProductDoc>>(...)
export default model<TSchema<IProductDoc>>("Product", ProductSchema);
The TSchema
used is from https://github.com/Automattic/mongoose/issues/9715 in courtesy of https://github.com/Automattic/mongoose/issues/9715#issuecomment-816146242. The IBrandDoc
is just something similar to IProductDoc
but on another model. I made my own working base document as stated in Mongoose Docs on TypeScript Support.
There’s nothing really wrong with the inheritance pattern described in the blogpost. It does work when an interface has no references to another model and the typesetting is sufficiently strong. However, when it is used in findByIdAndUpdate()
, it creates the type error above. As far as I know, findOneAndUpdate()
, updateOne()
, and updateMany()
also produces similar errors.
const data: IProduct = {
brand: args.brand,
// ...
};
const savedProduct = await new Product(data).save(); // works!
const updatedProduct = await Product.findByIdAndUpdate(
args._id,
data, //! Error: Type 'Record<string, any>' is not assignable to type 'string'. ts(2769)
options
);
My tsconfig.json
:
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"rootDir": "./",
"moduleResolution": "node",
"baseUrl": "./src",
"typeRoots": ["@types"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"exclude": ["./dist"]
}
What is the expected behavior?
I don’t really know if I’m doing something wrong there, but it should work as is given that the IProduct
interface works perfectly with the other model methods. Interfaces without references to other models work like a charm.
A temporary workaround would be to cast the data
object above to any
(e.g., <any>data
) when using it as an argument in findByIdAndUpdate()
, but I don’t know the future implications for this. I wonder if the blogpost is outdated now that Mongoose v6 is out.
What are the versions of Node.js, Mongoose and MongoDB you are using? Note that “latest” is not a version.
Node: v17.1.0 Mongoose: v6.0.12 MongoDB: v4.1.4 (did not explicitly install, it is a dep from when Mongoose was installed)
Update:
Took a little breather and it turns out I just needed to use the IProductDoc
instead of just the IProduct
since updating meant that it assumes it’s already a saved document. In other words, it already has an _id
and such. No errors ever since. My bad. I guess the takeaway here is that when the going gets tough, just don’t forget to take a break sometimes.
Update 11/20/21:
I retract my earlier revelation. I do in fact need data
to be just the plain IProduct
instead of the IProductDoc
. I just found out I can’t append the _id
in the update
params for use in findByIdAndUpdate()
as it gives the expected "_id" to be unique
error, so using IProductDoc
gives object creation type errors. Found something similar on https://github.com/Automattic/mongoose/issues/10689.
Issue Analytics
- State:
- Created 2 years ago
- Comments:6
If it works in 6.1.1 then this issue should be ok to close
Strange, upgrading to 6.1.1 for me actually removed the error. I can confirm it now runs fine from both my codebase (local and live) and codesandbox without any casting. I guess I still can’t close this one then.