[英]TypeScript - How to define model in combination with using mongoose populate?
我在我的 Node.JS 應用程序中使用 mongoose 和 TypeScript。 從數據庫中獲取數據時,我在很多地方使用貓鼬populate
。
我面臨的問題是我不知道如何鍵入我的模型,以便屬性可以是 ObjectId 或填充來自另一個集合的數據。
我嘗試在我的 model 類型定義中使用聯合類型,這似乎是 TypeScript 提供的涵蓋此類內容的東西:
interface User extends Document {
_id: Types.ObjectId;
name: string
}
interface Item extends Document {
_id: Types.ObjectId;
// Union typing here
user: Types.ObjectId | User;
}
我的架構僅將屬性定義為帶有 ref 的 ObjectId。
const ItemSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: "User", index: true }
})
示例:
所以我可能會這樣做:
ItemModel.findById(id).populate("user").then((item: Item) => {
console.log(item.user.name);
})
這會產生編譯錯誤:
[ts] Property 'name' does not exist on type 'User | ObjectId'.
Property 'name' does not exist on type 'ObjectId'.
我怎樣才能擁有一個 model 屬性,它可以是 TypeScript 中的兩種類型之一?
您需要使用類型保護來縮小Types.ObjectId | User
的類型Types.ObjectId | User
Types.ObjectId | User
對User
...
如果你正在處理一個User
類,你可以使用這個:
if (item.user instanceof User) {
console.log(item.user.name);
} else {
// Otherwise, it is a Types.ObjectId
}
如果您有一個與User
匹配的結構,但不是一個類的實例(例如,如果User
是一個接口),您將需要一個自定義類型保護:
function isUser(obj: User | any) : obj is User {
return (obj && obj.name && typeof obj.name === 'string');
}
您可以使用它:
if (isUser(item.user)) {
console.log(item.user.name);
} else {
// Otherwise, it is a Types.ObjectId
}
如果您不想為此目的檢查結構,您可以使用有區別的 union 。
當用戶被填充時,將item.user
為User
。
ItemModel.findById(id).populate("user").then((item: Item) => {
console.log((<User>item.user).name);
})
您可以使用@types/mongoose
庫中的PopulatedDoc
類型。 請參閱mongoose.doc 。
Mongoose 的 TypeScript 綁定導出 PopulatedDoc 類型,可幫助您在 TypeScript 定義中定義填充文檔:
import { Schema, model, Document, PopulatedDoc } from 'mongoose';
// `child` is either an ObjectId or a populated document
interface Parent {
child?: PopulatedDoc<Child & Document>,
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) => {
// Works
doc.child.name.trim();
})
下面是 PopulatedDoc 類型的簡化實現。 它需要 2 個通用參數:填充的文檔類型 PopulatedType 和未填充的類型 RawId。 RawId 默認為 ObjectId。
type PopulatedDoc<PopulatedType, RawId = Types.ObjectId> = PopulatedType | RawId;
您作為開發人員負責在填充和非填充文檔之間強制執行強類型。 下面是一個例子。
ParentModel.findOne({}).populate('child').orFail().then((doc: Parent) => {
// `doc` doesn't have type information that `child` is populated
useChildDoc(doc.child);
});
// You can use a function signature to make type checking more strict.
function useChildDoc(child: Child): void {
console.log(child.name.trim());
}
這是從文檔中提取的。 你可以在這里查看
抱歉來晚了,但這是使用 typescript 填充的官方方式。
ItemModel.findById(id).populate<{user:
{ _id: ObjectId, name: string; email: string}
}>("user").then((item: Item) => {
console.log(item.user.name);
})
或者
interface User { user: {_id: ObjectId, name: string; email: string} }
ItemModel.findById(id).populate<User>("user").then((item: Item) => {
console.log(item.user.name);
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.