typescript - Wie definiert man Instanz-/Dokumentmethoden in einem Mongoose-Modell, ohne sie in das Dokumentinterface einzuschließen
In der offiziellen Dokumentation zur Verwendung von Mongoose mit TypeScript heißt es in Bezug auf die Erweiterung des mongoose.Document-Typs bei der Bereitstellung einer Typdefinition:
Dieser Ansatz funktioniert, aber wir empfehlen, dass Ihre Dokumentenschnittstelle nicht Document erweitert. Die Verwendung von extends Document erschwert es Mongoose, zu erkennen, welche Eigenschaften in Abfragefiltern, schlanken Dokumenten und anderen Fällen vorhanden sind.
Wir empfehlen, dass Ihre Dokumentenschnittstelle die in Ihrem Schema definierten Eigenschaften enthält und mit dem übereinstimmt, wie Ihre Dokumente in MongoDB aussehen. Obwohl Sie Instanzmethoden zu Ihrer Dokumentenschnittstelle hinzufügen können, empfehlen wir dies nicht.
Bezüglich der letzten Zeile des zweiten Absatzes: Wenn empfohlen wird, Instanz-/Dokumentmethoden nicht in das Dokument-Interface aufzunehmen — wie sollten wir diese Informationen bereitstellen? Ohne die Definition dieser Methoden im Dokument-Interface wirft TypeScript einen Fehler, dass Property <Methodenname einfügen> does not exist on type <Dokumenttyp einfügen>.
Betrachten wir zum Beispiel die folgende Definition für einen Benutzer:
// user.model.ts
import { model, Schema } from 'mongoose';
import { UserDoc } from '../types/user.d.ts';
const userSchema = new Schema<UserDoc, Model<UserDoc>, UserDoc>({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
password: { type: String, required: true, trim: true }
});
userSchema.virtual('fullName').get(function (this: UserDoc) {
return `${this.firstName} ${this.lastName}`
});
userSchema.method('getFullName', function () {
return `${this.firstName} ${this.lastName}`
})
export default model<UserDoc, Model<UserDoc>>('User', userSchema)
Die UserDoc-Schnittstelle wird wie folgt definiert:
export interface UserDoc {
firstName: string;
lastName: string;
email: string;
password: string;
}
Ohne die virtuelle Eigenschaft fullName oder die Instanzmethode getFullName im UserDoc-Interface explizit zu definieren, kann auf keine von beiden zugegriffen werden.
Betrachten Sie zum Beispiel den folgenden Express-Route-Handler, um einen neuen Benutzer zu registrieren:
import { RequestHandler } from 'express';
import User from '../models/user.model.ts'; // The model as defined in the above userSchema
const registerUserHandler: RequestHandler = async (req, res, next) => {
const { firstName, lastName, email, password } = req.body;
if (await User.exists({ email })) {
return res.status(400).json('Email already exists')
}
const newUser = await User.create({ firstName, lastName, email, password });
console.log(newUser.fullName) // This will cause typescript error
console.log(newUser.getFullName()) // This will cause typescript error
return res.status(201).json('User created')
}
Wenn jedoch die UserDoc-Schnittstelle erweitert wird, um das fullName-Virtual und die getFullName-Methode einzuschließen, wird TypeScript keinen Fehler anzeigen und den Zugriff erlauben.
Beim Blick auf die offizielle Dokumentation für statische Methoden wird angegeben, dass Sie diese einbeziehen und die mongoose.Model<T>-Schnittstelle erweitern müssen.
Wenn wir diese also nicht auf der Dokumentenoberfläche platzieren sollen, wie sollen wir sie dann definieren, damit TypeScript den Zugriff erlaubt?