Skip to content

Latest commit

 

History

History
88 lines (70 loc) · 2.55 KB

subdocuments.md

File metadata and controls

88 lines (70 loc) · 2.55 KB

Handling Subdocuments in TypeScript

Subdocuments are tricky in TypeScript. By default, Mongoose treats object properties in document interfaces as nested properties rather than subdocuments.

// Setupimport{Schema,Types,model,Model}from'mongoose';// Subdocument definitioninterfaceNames{_id: Types.ObjectId;firstName: string;}// Document definitioninterfaceUser{names: Names;}// Models and schemastypeUserModelType=Model<User>;constuserSchema=newSchema<User,UserModelType>({names: newSchema<Names>({firstName: String})});constUserModel=model<User,UserModelType>('User',userSchema);// Create a new document:constdoc=newUserModel({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 provides a mechanism to override types in the hydrated document. Define a separate THydratedDocumentType and pass it as the 5th generic param to mongoose.Model<>. THydratedDocumentType controls what type Mongoose uses for "hydrated documents", that is, what await UserModel.findOne(), UserModel.hydrate(), and new UserModel() return.

import{HydratedSingleSubdocument}from'mongoose';// Define property overrides for hydrated documentstypeTHydratedUserDocument={names?: HydratedSingleSubdocument<Names>}typeUserModelType=mongoose.Model<User,{},{},{},THydratedUserDocument>;constuserSchema=newmongoose.Schema<User,UserModelType>({names: newmongoose.Schema<Names>({firstName: String})});constUserModel=mongoose.model<User,UserModelType>('User',userSchema);constdoc=newUserModel({names: {_id: '0'.repeat(24),firstName: 'foo'}});doc.names!.ownerDocument();// Works, `names` is a subdocument!doc.names!.firstName;// 'foo'

Subdocument Arrays

You can also override arrays to properly type subdocument arrays using TMethodsAndOverrides:

// Subdocument definitioninterfaceNames{_id: Types.ObjectId;firstName: string;}// Document definitioninterfaceUser{names: Names[];}// TMethodsAndOverridestypeTHydratedUserDocument={names?: Types.DocumentArray<Names>}typeUserModelType=Model<User,{},{},{},THydratedUserDocument>;// Create modelconstUserModel=model<User,UserModelType>('User',newSchema<User,UserModelType>({names: [newSchema<Names>({firstName: String})]}));constdoc=newUserModel({});doc.names[0].ownerDocument();// Works!doc.names[0].firstName;// string
close