#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);
};
замечание
Пожалуйста, имейте в виду, что, согласно документам mongoose, можно настраивать .toObject
на уровне схемы и / или передавать параметры при вызове .toObject
. Правильный ввод этих вариантов использования выходит за рамки этого вопроса или вообще невозможен с текущей версией Typescript.
Ответ №2:
Вы могли бы использовать Omit<>
и заменить объявление типа ToObject
export interface IUserModel extends Omit<Document, 'toObject'>, IUser {
toObject: () => IUserObject;
}