Как Typescript mongoose ToObject?

#typescript #mongoose

#typescript #mongoose

Вопрос:

Каков правильный способ ввода .toObject() return?

 const userDoc = await UsersModel.findOne({email})
const user:IUserObject = userDoc.toObject()
 

Это user не IUserObject так. Его ввод не имеет смысла : Pick<Pick<_LeanDocument<IUserModel>, "_id"... .

Вот моя модель ввода:

 import {Schema, model, Document} from 'mongoose'

export interface IUser {
  email: string
  password: string
}

export interface IUserObject extends IUser {
  _id: string
}

export interface IUserModel extends Document, IUser {}

const schema = new Schema({
  email: { type: String, required: true },
  password: { type: String, required: true }
})

export const UsersModel = model<IUserModel>('Users', schema)
 

Комментарии:

1. Я не думаю, что здесь есть хороший ответ. Объявления типов для mongoose неясны и громоздки. Вы можете либо принудительно ввести тип в свой интерфейс, либо использовать вычисляемый тип mongoose. Я бы сказал, что я думаю, что есть много преимуществ для проверки данных, полученных из базы данных, которая предлагает написать функцию validateRetrieved(data: unknown): IUser, которая решает вашу первоначальную проблему

Ответ №1:

Исходный тип Mongoose для doc.toObject() выглядит действительно запутанным и, скорее всего, происходит от времени до условных типов и infer оператора. Что еще хуже, это кажется неправильным представлением значения времени выполнения, которое, согласно документам mongoose, должно быть просто POJO:

 type ToObjectReturnType = ReturnType<Document<IUser>['toObject']>
/*
  ToObjectReturnType = {
    _id?: IUser;
    __v?: number;
    id?: any;
  }
*/
 

Возможным решением / улучшением без устранения основной проблемы в mongoose может быть использование вспомогательной функции для вывода базовой модели из документа и вызова doc.toObject :

 // a generic method for infering underlying Model out of a mongoose Document
// and interecting it with { _id: string }
const docToObject = <D extends Document<any>>(doc: D) =>
  doc.toObject() as D extends Document<infer Model>
    ? Model amp; { _id: string } // not sure if _id is always there - please modify to your needs / real runtime value
    : never;

// example of usage
const findUserByEmail = async (email: string) => {
  const userDoc = await UsersModel.findOne({ email });
  return docToObject(userDoc);
};
 

STACKBLITZ

замечание

Пожалуйста, имейте в виду, что, согласно документам mongoose, можно настраивать .toObject на уровне схемы и / или передавать параметры при вызове .toObject . Правильный ввод этих вариантов использования выходит за рамки этого вопроса или вообще невозможен с текущей версией Typescript.

Ответ №2:

Вы могли бы использовать Omit<> и заменить объявление типа ToObject

 export interface IUserModel extends Omit<Document, 'toObject'>, IUser {
      toObject: () => IUserObject;
}