打字稿和猫鼬:“文档”类型上不存在属性“x”
Posted
技术标签:
【中文标题】打字稿和猫鼬:“文档”类型上不存在属性“x”【英文标题】:Typescript and Mongoose: Property 'x' does not exist on type 'Document' 【发布时间】:2021-02-12 20:23:18 【问题描述】:这是我与 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);
我在我的控制器中使用这个模型:
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));
;
我收到以下错误:
“文档”类型上不存在属性“转换”。
“模型
”类型上不存在属性“checkDuplicateEmailError”。
我尝试了export default mongoose.model<any>("User", userSchema);
,但没有收到transform
错误,但仍然是checkDuplicateEmailError
的错误。
【问题讨论】:
这里有不少TS错误。我在transformed[field]
上看到红色下划线,我很惊讶err.code
上没有警告,因为err
是any
。您需要一堆注释,包括将User
定义为具有transform()
方法。我会给你写一个答案,但我必须检查文档中的一些内容,因为我对 TS 的了解比对猫鼬的了解要多得多。
【参考方案1】:
您知道mongoose.model("User", userSchema);
创建了一个Model
,但问题是:什么模型?
在没有任何类型注释的情况下,模型User
获取类型Model<Document, >
,从new User()
创建的user
对象获取类型Document
。因此,您当然会收到类似 “类型 'Document' 上不存在属性 'transform'。”之类的错误。
当您添加 <any>
变量时,user
的类型变为 any
。这实际上给我们的信息比知道user
是Document
要少。
我们要做的是为描述我们用户的特定类型的Document
创建一个模型。用户的实例应该有一个方法transform()
,而模型本身应该有一个方法checkDuplicateEmailError()
。我们通过将泛型传递给mongoose.model()
函数来做到这一点:
export default mongoose.model<UserDocument, UserModel>("User", userSchema);
困难的部分是找出这两种类型。令人沮丧的是,尽管there are packages that do this,猫鼬不会自动将架构中的字段应用为类型的属性。所以我们必须把它们写成打字稿类型。
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
是UserDocument
的Model
,它还包括我们的checkDuplicateEmailError
函数。
interface UserModel extends Model<UserDocument>
checkDuplicateEmailError(err: any): any;
我们还应该在创建Schema
时添加UserDocument
泛型,这样当我们在架构方法中访问this
时,它的类型就会是UserDocument
。
const userSchema = new Schema<UserDocument>(
我在尝试实现 transform()
方法时遇到了各种打字错误,包括缺少索引签名。通过使用lodash
中的pick
方法,我们可以避免在这里重新发明***。我仍然对 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
是undefined
,则尝试访问属性err.code
。
if ( typeof err === "object" && err.code === 11000)
这应该可以解决您的所有错误。
Playground Link
【讨论】:
以上是关于打字稿和猫鼬:“文档”类型上不存在属性“x”的主要内容,如果未能解决你的问题,请参考以下文章