Populate with TypeScript使用TypeScript填充
Mongoose's TypeScript bindingsMongoose的TypeScript绑定 add a generic parameter 将泛型参数Paths
to the populate()
:Paths
添加到populate()
中:
import { Schema, model, Document, Types } from 'mongoose';
// `Parent` represents the object as it is stored in MongoDB
interface Parent {
child?: Types.ObjectId,
name?: string
}
const ParentModel = model<Parent>('Parent', new Schema({
child: { type: Schema.Types.ObjectId, ref: 'Child' },
name: String
}));
interface Child {
name: string;
}
const childSchema: Schema = new Schema({ name: String });
const ChildModel = model<Child>('Child', childSchema);
// Populate with `Paths` generic `{ child: Child }` to override `child` path
ParentModel.findOne({}).populate<{ child: Child }>('child').orFail().then(doc => {
// Works
const t: string = doc.child.name;
});
An alternative approach is to define a 另一种方法是定义一个PopulatedParent
interface and use Pick<>
to pull the properties you're populating.PopulatedParent
接口,并使用Pick<>
来提取正在填充的属性。
import { Schema, model, Document, Types } from 'mongoose';
// `Parent` represents the object as it is stored in MongoDB
interface Parent {
child?: Types.ObjectId,
name?: string
}
interface Child {
name: string;
}
interface PopulatedParent {
child: Child | null;
}
const ParentModel = model<Parent>('Parent', new Schema({
child: { type: Schema.Types.ObjectId, ref: 'Child' },
name: String
}));
const childSchema: Schema = new Schema({ name: String });
const ChildModel = model<Child>('Child', childSchema);
// Populate with `Paths` generic `{ child: Child }` to override `child` path
ParentModel.findOne({}).populate<Pick<PopulatedParent, 'child'>>('child').orFail().then(doc => {
// Works
const t: string = doc.child.name;
});
Using PopulatedDoc
使用PopulatedDoc
PopulatedDoc
Mongoose also exports a Mongoose还导出一个PopulatedDoc
type that helps you define populated documents in your document interface:PopulatedDoc
类型,帮助您在文档界面中定义已填充的文档:
import { Schema, model, Document, PopulatedDoc } from 'mongoose';
// `child` is either an ObjectId or a populated document
interface Parent {
child?: PopulatedDoc<Document<ObjectId> & Child>,
name?: string
}
const ParentModel = model<Parent>('Parent', new Schema({
child: { type: 'ObjectId', ref: 'Child' },
name: String
}));
interface Child {
name?: string;
}
const childSchema: Schema = new Schema({ name: String });
const ChildModel = model<Child>('Child', childSchema);
ParentModel.findOne({}).populate('child').orFail().then((doc: Parent) => {
const child = doc.child;
if (child == null || child instanceof ObjectId) {
throw new Error('should be populated');
} else {
// Works
doc.child.name.trim();
}
});
However, we recommend using the 但是,我们建议使用第一节中的.populate<{ child: Child }>
syntax from the first section instead of PopulatedDoc
. Here's two reasons why:.populate<{ child: Child }>
语法,而不是PopulatedDoc
。原因有两个:
You still need to add an extra check to check if您仍然需要添加一个额外的检查来检查child instanceof ObjectId
.child instanceof ObjectId
。Otherwise, the TypeScript compiler will fail with否则,TypeScript编译器将失败,因为Property name does not exist on type ObjectId
.Property name does not exist on type ObjectId
。So using因此,使用PopulatedDoc<>
means you need an extra check everywhere you usedoc.child
.PopulatedDoc<>
意味着您需要在任何使用doc.child
的地方进行额外检查。In the在Parent
interface,child
is a hydrated document, which makes it slow difficult for Mongoose to infer the type ofchild
when you uselean()
ortoObject()
.Parent
接口中,child
是一个水合文档,这使得Mongoose在使用lean()
或toObject()
时很难推断出child的类型。