MongoDB Node.js中调用updateOne方法时出现TypeScript编译错误的排查请求
错误原因分析
我刚排查过几乎一模一样的问题,你的错误本质是两个核心问题叠加导致的:
updateOne参数调用错误
Mongoose的updateOne方法需要两个必填参数:第一个是筛选条件(用来定位要修改的文档),第二个才是要更新的内容。但你的代码只传了一个对象,TypeScript会把这个对象当成filter(筛选条件)来校验,而不是更新内容。类型不兼容 + 严格模式约束
你用了updatePayLoad.data?.firstName这种可选链,导致属性可能为undefined,但你的Mongoose用户模型中firstName、lastName是必填的string类型,再加上TypeScript开启了exactOptionalPropertyTypes严格模式,不允许把undefined赋值给非可选的属性,所以触发了TS2769错误。
另外,你的Zod schema定义的是三个必填字段,但代码中却用了可选链访问,这说明要么你在Zod校验前就访问了属性,要么updatePayLoad的类型没有和Zod schema绑定,导致TypeScript无法推断出属性的非空性。
可行解决方案
方案1:修正updateOne调用逻辑(最关键)
先明确筛选条件(比如用户ID、邮箱),再把更新内容放到第二个参数,用Mongoose推荐的$set操作符:
// 假设你通过请求参数拿到了要更新的用户ID const userId = req.params.userId; // 先通过Zod校验确保数据合法(此时属性都是非空的string) const validatedData = updateValidation.parse(updatePayLoad.data); // 调用updateOne的正确姿势:筛选条件 + 更新内容 const response = await userModel.updateOne( { _id: userId }, // 第一个参数:定位要更新的文档 { $set: { ...validatedData, password: hashedPassword } } // 第二个参数:要更新的字段 );
方案2:支持部分字段可选更新(如果需求允许)
如果用户不需要同时修改三个字段,可修改Zod schema为可选字段,再过滤掉undefined属性:
// 修改Zod schema,允许部分字段可选 export const updateValidation = z.object({ firstName: z.string().optional(), lastName: z.string().optional(), password: z.string() // 密码必填,或者也设为optional }); // 校验后过滤掉undefined属性,避免传给Mongoose const validatedData = updateValidation.parse(updatePayLoad.data); const filteredUpdate = Object.fromEntries( Object.entries({ ...validatedData, password: hashedPassword }).filter(([_, val]) => val !== undefined) ); // 调用updateOne const response = await userModel.updateOne( { _id: userId }, { $set: filteredUpdate } );
方案3:临时关闭严格模式(不推荐)
如果不想修改代码,可在tsconfig.json中关闭exactOptionalPropertyTypes,但这会降低TypeScript的类型检查能力,不建议长期使用:
{ "compilerOptions": { "exactOptionalPropertyTypes": false } }
额外提示
- 确保Zod校验在数据访问前执行,这样TypeScript就能通过Zod的类型推断知道属性是非空的,不需要再用
?.可选链。 - 始终用
$set操作符更新字段,避免意外覆盖整个文档。
内容的提问来源于stack exchange,提问作者Adarsh Singh

