在 TypeScript 中處理子文檔
子文檔在 TypeScript 中比較棘手。預設情況下,Mongoose 將文檔介面中的物件屬性視為巢狀屬性,而不是子文檔。
// Setup
import { Schema, Types, model, Model } from 'mongoose';
// Subdocument definition
interface Names {
_id: Types.ObjectId;
firstName: string;
}
// Document definition
interface User {
names: Names;
}
// Models and schemas
type UserModelType = Model<User>;
const userSchema = new Schema<User, UserModelType>({
names: new Schema<Names>({ firstName: String })
});
const UserModel = model<User, UserModelType>('User', userSchema);
// Create a new document:
const doc = new UserModel({ names: { _id: '0'.repeat(24), firstName: 'foo' } });
// "Property 'ownerDocument' does not exist on type 'Names'."
// Means that `doc.names` is not a subdocument!
doc.names.ownerDocument();
Mongoose 提供了一種機制來覆寫水合文檔中的類型。定義一個單獨的 THydratedDocumentType
,並將其作為第 5 個泛型參數傳遞給 mongoose.Model<>
。THydratedDocumentType
控制 Mongoose 用於「水合文檔」的類型,也就是 await UserModel.findOne()
、UserModel.hydrate()
和 new UserModel()
所返回的內容。
// Define property overrides for hydrated documents
type THydratedUserDocument = {
names?: mongoose.Types.Subdocument<Names>
}
type UserModelType = mongoose.Model<User, {}, {}, {}, THydratedUserDocument>;
const userSchema = new mongoose.Schema<User, UserModelType>({
names: new mongoose.Schema<Names>({ firstName: String })
});
const UserModel = mongoose.model<User, UserModelType>('User', userSchema);
const doc = new UserModel({ names: { _id: '0'.repeat(24), firstName: 'foo' } });
doc.names!.ownerDocument(); // Works, `names` is a subdocument!
子文檔陣列
您也可以使用 TMethodsAndOverrides
覆寫陣列,以正確鍵入子文檔陣列
// Subdocument definition
interface Names {
_id: Types.ObjectId;
firstName: string;
}
// Document definition
interface User {
names: Names[];
}
// TMethodsAndOverrides
type THydratedUserDocument = {
names?: Types.DocumentArray<Names>
}
type UserModelType = Model<User, {}, {}, {}, THydratedUserDocument>;
// Create model
const UserModel = model<User, UserModelType>('User', new Schema<User, UserModelType>({
names: [new Schema<Names>({ firstName: String })]
}));
const doc = new UserModel({});
doc.names[0].ownerDocument(); // Works!