Search code examples
typescriptmongoosetypes

Why are subdocuments possibly undefined in Mongoose?


Given a subdocument within a Mongoose schema:

const someSchema = new Schema(
  {
    sub: {
      val: { type: String, default: "" },
    },

    // other properties ...
  }
);

The type of sub shown by TypeScript is:

(property) sub?: {
    val: string;
} | null | undefined

This becomes a problem when inferring the type of the parent document using Mongoose's InferSchemaType Utility:

type Doc = InferSchemaType<typeof someSchema>
//   ^? type Doc = {
//  sub?: {
//      val: string;
//  } | null | undefined;

How can I ensure that sub is not possibly null or undefined?


Solution

  • According to https://mongoosejs.com/docs/subdocs.html

    Mongoose applies defaults recursively, which means there's a nice workaround if you want to make sure Mongoose applies subdocument defaults: make the subdocument path default to an empty object.

    To ensure that the sub subdocument is not null or undefined, move the current children inside a type property, and apply a default empty object to the subdocument like so:

    const someSchema = new Schema(
      {
        sub: {
          default: () => ({}),
          type: {
            val: { type: String, default: "" },
          }
        },
    
        // other properties ...
      }
    );
    

    This will result in the following Doc type:

    type Doc = InferSchemaType<typeof someSchema>
    //   ^? type Doc = {
    //  sub: {
    //      val: string;
    //  };