【问题标题】:How to type Mongo fields that are automatically created in typescript?如何键入在打字稿中自动创建的 Mongo 字段?
【发布时间】:2021-10-30 13:57:50
【问题描述】:

这是我的模型,紧跟 the docs for mongoose v5.13.x with TypeScript:


import mongoose, { Model, Schema, Types } from "mongoose";

export interface Foo {
  label: string;

  archived: boolean;
  created_at: number;
  updated_at: number;
}

const FooSchema = new Schema<Foo, Model<Foo>, Foo>(
  {
    label: { type: String },

    archived: { type: Boolean, default: false },
  },
  {
    timestamps: {
      createdAt: "created_at",
      updatedAt: "updated_at",
      currentTime: () => Date.now() / 1000,
    },
  }
);

const Foo: Model<Foo> = mongoose.model<Foo>("Foo", FooSchema);

好的,现在我想要创建和检索模型的函数。当我创建它时,自动创建的字段如_idarchivedcreated_atupdated_at 都应该是可选的。但是当我检索它时,它们应该都可用。例如:


type FooInput = {
  label: string;
};

type FooOutput = {
  _id: string;
  label: string;
  archived: boolean;
  created_at: number;
  updated_at: number;
};

export const createFoo = async (foo: FooInput): Promise<FooOutput> => {
  return await Foo.create(foo);
};

但是,这会左右抛出类型错误;它会说_idFoo.create() 的输出中是可选的,如果我将它添加到我的类型中,Foo.create(foo) 会感到不安。

在这种情况下,键入_idcreated_at 等字段的正确方法是什么?

【问题讨论】:

    标签: typescript mongodb express mongoose


    【解决方案1】:

    似乎Model.create() 是一个非常类型不安全的方法,所以我发现我需要自己声明它,以及FooInput 类型的Omits 字段可以有默认值。

    我需要创建一个TypesafeModel 来覆盖Modelcreateupdate 方法,但这感觉不太好。

    import mongoose, { Model, Schema, Types, EnforceDocument, FilterQuery } from "mongoose";
    
    interface TypesafeModel<D, I = Partial<D>, QueryHelpers = {}, Methods = {}> extends Omit<Model<D, QueryHelpers, Methods>, 'create' | 'update'> {
      create(doc: I): Promise<EnforceDocument<D, Methods>>,
      update(filter: FilterQuery<D>, doc: Partial<I>): Promise<EnforceDocument<D, Methods>>,
    }
    
    export type Foo = {
      _id: Types.ObjectId,
      label: string;
      extra?: string;
    
      archived: boolean;
      created_at: number;
      updated_at: number;
    }
    
    type FooFieldsWithDefaults = '_id' | 'archived' | 'created_at' | 'updated_at'
    type FooInput = Omit<Foo, FooFieldsWithDefaults>
    
    
    interface FooQueryHelpers {}
    interface FooMethods {}
    
    interface FooModel extends TypesafeModel<Foo, FooInput, FooQueryHelpers, FooMethods> {
      // statics go here
    }
    
    const FooSchema = new Schema<Foo, FooModel, Foo>(
      {
        label: { type: String, required: true },
        extra: { type: String },
    
        archived: { type: Boolean, default: false },
      },
      {
        timestamps: {
          createdAt: "created_at",
          updatedAt: "updated_at",
          currentTime: () => Date.now() / 1000,
        },
      }
    );
    
    const Foo = mongoose.model<Foo, FooModel>("Foo", FooSchema);
    
    export const createFoo = async (foo: FooInput): Promise<Foo> => {
      const good = await Foo.create(foo); 
      const bad = await Foo.create({ wrong: 'stuff' }); // hooray, a type error!
      const bad2 = await Foo.update({'_id': '123'}, { wrong: 'stuff'}); // hooray, a type error!
    
      return good
    };
    

    【讨论】:

      【解决方案2】:

      你可以让你的类型扩展mongoose.Document

      【讨论】:

      • the docs 中建议反对:“我们建议您的文档界面不要扩展 Document”
      猜你喜欢
      • 2021-03-04
      • 2018-04-27
      • 2019-11-28
      • 2022-12-22
      • 2020-05-21
      • 2021-12-17
      • 1970-01-01
      • 2018-07-29
      • 1970-01-01
      相关资源
      最近更新 更多