Как вы заполняете объекты mongoose значениями на основе интерфейса?

#typescript #mongoose #nestjs #typescript-typings

#typescript #mongoose #nestjs #typescript-типизации

Вопрос:

Я работаю над API NestJS и пытаюсь создать некоторые документы с помощью mongoose, но я сталкиваюсь с некоторыми проблемами. Я следил за документами NestJS Mongo и руководством по Auth0 API, чтобы получить хорошее представление о том, что вы должны делать.

[ПРИМЕЧАНИЕ] Я удалил все очевидные и выходящие за рамки импорта блоки кода. Я также зарегистрировал модели, какими они должны быть, так что здесь тоже не о чем спрашивать. Также необходимо, чтобы я мог заполнять значения самостоятельно, поскольку в реальном продукте я должен выполнять вычисления для заполнения значений. Вот почему я решил сначала заполнить значения, вместо того, чтобы просто передавать DTO объекту mongoose.

Это мой объект документа mongoose:

 // src/user/interfaces/user.interface.ts
import { Document } from 'mongoose';

export interface User extends Document {
   readonly string firstName;
   readonly string lastName;
   readonly string fullName;
}
  

Но .. когда я пытаюсь заполнить значения в сервисе следующим образом:

 // src/user/user.service.ts
import { User } from './interfaces/user.interface';

@Injectable();
export class UserService {
  constructor(
    @InjectModel("User")
    private readonly userModel: Model<User>,
  ) {}

  async createUser(dto: CreateUserDTO): Promise<User> {
    const user: User = {
       firstName: dto.firstName,
       lastName: dto.lastName,
       fullName: `${dto.firstName} ${dto.lastName}`,
    }
    return await this.userModel.create(user);
  }
}
  

Это приводит к следующей ошибке и не компилируется:

 Type '{ firstName: string; lastName: string; fullName: string; }'
  is missing the following properties from type 'User': increment, model, $isDeleted, remove, and 52 more.ts(2740)
  

Это, конечно, ошибки, поскольку он расширяет документ Mongoose, и эти значения не заполняются.


Я уже пробовал следующее, но мне не понравились «решения»

Попытка 1

Передайте это напрямую в качестве аргумента, к сожалению, это не дает мне автозаполнения и проверки

 async createUser(dto: CreateUserDTO): Promise<User> {
  const newUser = new this.userModel({
    firstName: dto.firstName,
    lastName: dto.lastName,
    fullName: `${dto.firstName} ${dto.lastName}`,
  });
  return await newUser.save();
}
  

Попытка 2

Создайте второй интерфейс и используйте интерфейс A при заполнении и интерфейс B при возврате и вызове

 // src/user/interfaces/user.interface.ts
import { Document } from 'mongoose';

export interface User {
   readonly string firstName;
   readonly string lastName;
   readonly string fullName;
}

export interface UserDoc extends User, Document {}
  

а затем используете его в сервисе, например:

 // src/user/user.service.ts
import { User, UserDoc } from './interfaces/user.interface';

@Injectable();
export class UserService {
  constructor(
    @InjectModel("User")
    private readonly userModel: Model<UserDoc>,
  ) {}

  async createUser(dto: CreateUserDTO): Promise<UserDoc> {
    const user: User = {
       firstName: dto.firstName,
       lastName: dto.lastName,
       fullName: `${dto.firstName} ${dto.lastName}`,
    }
    return await this.userModel.create(user);
  }
}
  

Теперь это работает, но это действительно некрасиво, и вам также нужно убедиться, что вы используете правильный интерфейс в нужное время, так что это довольно неудобно.


TL; DR; Есть ли способ создать строго типизированные объекты mongoose, в которые вы можете поместить значения, которые будут автоматически заполняться, как в Attempt B , но лучше и чище?