使用节点和猫鼬实现接口的正确方法是什么?

What is the correct way to implement interfaces with node and mongoose?

我为我的模型创建了一个界面,我只想return记录中的特定数据

// code.interface.ts
import { Document } from 'mongoose';

export interface CodeI extends Document {
  readonly _id: string;
  readonly logs: any;
}

但是当我从 mongo 得到结果时,它完全忽略了我界面中的内容。 (我正在使用 NestJs 作为框架)

 //constructor
   constructor(@InjectModel(Coupon.name) private couponModel: Model<CouponDocument>) {}

 // function
 async findOne(codeId: string): Promise<CodeI> {
    const coupon = await this.couponModel.findOne({ _id: codeId }).exec();
    if (!coupon) {
      throw new NotFoundException([`#${codeId} not found`]);
    }
    return coupon;
  }

TypeScript 接口不是这样工作的。它们不能限制对象的字段,因为它们在运行时不存在,所以,我们不能用它们来指导任何运行时行为。 TypeScript 接口仅对编译时类型检查有用。

但是,对于您的情况,有两种方法可以实现预期的行为。

  1. 第一个是 select 仅 return 需要的必填字段(推荐)。

在你的 findOne 中,你可以做这样的事情

async findOne(codeId: string): Promise<CodeI> {
   const coupon = await this.couponModel.findOne({ _id: codeId }, '_id logs').exec();
   if (!coupon) {
     throw new NotFoundException([`#${codeId} not found`]);
   }
  return coupon;
}

在这里,如您所见,我向 findOne 函数传递了一个额外的字符串类型参数,它是投影,它将 select 仅从对象中指定的字段。这不仅可以解决您的问题,还可以节省查询时间并提高查询性能。 Read more about findOne here.

  1. 另一种方法是创建一个 DTO,您可以在其中定义要从函数中 return 的字段。 像这样:

// CouponDto.ts
class CouponDto {
    public readonly _id: string;
    public readonly logs: any;
    constructor(data: CodeI) {
        this._id = data._id;
        this.logs = data.logs;
    }
}

然后,在您的服务文件中,您可以执行类似

的操作
return new CouponDto(coupon);

(确保将函数的 return 类型也更改为 CouponDto

您可以使用这两种方式中的任何一种。虽然我建议使用第一个,但这取决于您以及您想要如何构建项目。

外部链接: