javascript - typescript 和 Mongoose : Property 'x' does not exist on type 'Document'

标签 javascript typescript mongoose mongoose-schema

这是我与 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, {}>usernew User() 创建的对象获取类型 Document .因此,您当然会收到诸如“'文档'类型上不存在属性'转换'”之类的错误。
当您添加 <any>变量,user 的类型变成了any .这实际上给我们的信息少于知道 userDocument .
我们要做的是为 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]>
我们的UserModelModelUserDocument它还包括我们的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 时出现运行时错误如果 errundefined .
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/

相关文章:

javascript - Mongoose ODM 在 MongoDB 集合中保存错误的模型名称

javascript - Phonegap Cordova Statusbar 插件创建双条

javascript - 如何在页面调整大小时刷新我的 jQuery Mobile 样式?

javascript - html - 如何动态更改网页的 url

typescript - 无法在本地测试云功能,模拟器无法启动并出现 TypeError : _onRequestWithOpts is not a function

node.js - Mongoose:更新单个子文档的问题

javascript - 为什么我的代码不能将变量的值打印到控制台?

javascript - 如何解决具有不同数据类型的 Angular 4 的方法重载问题?

javascript - 为什么 X === (A || B || C) 不匹配任何内容?

node.js - Express.js 项目中在哪里进行验证 – 数据库层验证(re. Mongoose)?