这是我与 TypeScript 一起使用的 Mongoose 模型:
import mongoose, { Schema } from "mongoose";
const userSchema: Schema = new Schema(
{
email: {
type: String,
required: true,
unique: true,
lowercase: true,
},
name: {
type: String,
maxlength: 50,
},
...
...
}
);
userSchema.method({
transform() {
const transformed = {};
const fields = ["id", "name", "email", "createdAt", "role"];
fields.forEach((field) => {
transformed[field] = this[field];
});
return transformed;
},
});
userSchema.statics = {
roles,
checkDuplicateEmailError(err: any) {
if (err.code === 11000) {
var error = new Error("Email already taken");
return error;
}
return err;
},
};
export default mongoose.model("User", userSchema);
我在我的 Controller 中使用这个模型:import { Request, Response, NextFunction } from "express";
import User from "../models/user.model";
import httpStatus from "http-status";
export const register = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const user = new User(req.body);
const savedUser = await user.save();
res.status(httpStatus.CREATED);
res.send(savedUser.transform());
} catch (error) {
return next(User.checkDuplicateEmailError(error));
}
};
我收到以下错误:Property 'transform' does not exist on type 'Document'.
Property 'checkDuplicateEmailError' does not exist on type 'Model<Document, {}>'.
我试过
export default mongoose.model<any>("User", userSchema);
我没有得到 transform
错误但仍然是 checkDuplicateEmailError
的错误.
最佳答案
你知道mongoose.model("User", userSchema);
创建一个 Model
,但问题是:什么模型?
没有任何类型注释,模型 User
获取类型 Model<Document, {}>
和 user
从 new User()
创建的对象获取类型 Document
.因此,您当然会收到诸如“'文档'类型上不存在属性'转换'”之类的错误。
当您添加 <any>
变量,user
的类型变成了any
.这实际上给我们的信息少于知道 user
是 Document
.
我们要做的是为 Document
的特定类型创建一个模型。描述我们的用户。用户的实例应该有一个方法transform()
而模型本身应该有方法checkDuplicateEmailError()
.我们通过将泛型传递给 mongoose.model()
来做到这一点。功能:
export default mongoose.model<UserDocument, UserModel>("User", userSchema);
困难的部分是弄清楚这两种类型。令人沮丧的是,虽然 there are packages that do this mongoose 不会自动将架构中的字段应用为类型的属性。 .所以我们必须把它们写成 typescript 类型。interface UserDocument extends Document {
id: number;
name: string;
email: string;
createdAt: number;
role: string;
transform(): Transformed;
}
我们的transform
函数从 UserDocument
返回一个具有 5 个特定属性的对象。 .为了访问这些属性的名称而不必再次键入它们,我移动了 fields
从您的transform
内部方法成为顶级属性。我用了as const
将它们的类型保留为字符串文字,而不仅仅是 string
. (typeof transformFields)[number]
给我们这些字符串的联合。const transformFields = ["id", "name", "email", "createdAt", "role"] as const;
type Transformed = Pick<UserDocument, (typeof transformFields)[number]>
我们的UserModel
是 Model
的 UserDocument
它还包括我们的checkDuplicateEmailError
功能。interface UserModel extends Model<UserDocument> {
checkDuplicateEmailError(err: any): any;
}
我们还应该添加 UserDocument
当我们创建 Schema
时是通用的,所以 this
将具有类型 UserDocument
当我们在模式方法中访问它时。const userSchema = new Schema<UserDocument>({
我在尝试实现 transform()
时遇到了各种各样的打字错误。方法包括缺少索引签名。我们可以通过使用 pick
来避免在这里重新发明轮子。来自 lodash
的方法.我仍然对 Mongoose 有问题 methods()
辅助函数,但使用直接分配方法可以正常工作。userSchema.methods.transform = function (): Transformed {
return pick(this, transformFields);
};
您还可以使用解构来避免索引签名问题。userSchema.methods.transform = function (): Transformed {
const {id, name, email, createdAt, role} = this;
return {id, name, email, createdAt, role};
}
在您的电子邮件检查功能中,我添加了 typeof
检查以避免尝试访问属性 err.code
时出现运行时错误如果 err
是 undefined
.if ( typeof err === "object" && err.code === 11000) {
那应该可以解决您的所有错误。Playground Link
关于javascript - typescript 和 Mongoose : Property 'x' does not exist on type 'Document' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64607253/