Skip to content

TS: _id not required on DocumentArray properties of documents returned from query #14660

Closed
@alukach

Description

@alukach

Prerequisites

  • I have written a descriptive issue title

Mongoose version

8.2.3

Node.js version

20.14.0

MongoDB version

?

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

14.1

Issue

I have a Mongoose model which has a subdocument. I have a function that queries the model via the .find() method. The function's output is expected to conform to an output interface, however it is not playing nicely with the the auto-generated TypeScript types for the model. The mongoose docs state: "Each subdocument has an _id by default", however the types for the DocumentArray properties returned from a find() operation do not have _id marked as required.

This feels like a bug on the Mongoose side but I am new to using the library so it's possible that I'm missing something.

Questions:

  • Am I correct that it is safe to assume that any subdocuments will have an _id property when a document is retrieved via the .find() operations? (safe for any situations where I explicitly instruct Mongoose to not place an _id on the subdocument, of course)
  • Short of a change in mongoose code itself, how can I customize the output of the types in a succinct manner? I'd prefer to not write my own types for the Schema and Model as mongoose does a good job inferring these values and I would like to avoid maintaining redundant code. I see that .find() is a generic function (link), so I could provide my own type that instructs mongoose that the _id is required, however I'm struggling to achieve that.

Simplified example:

import mongoose from 'mongoose';

const ChildSchema = new mongoose.Schema({
  name: { type: String, required: true },
});

const ParentSchema = new mongoose.Schema({
  _id: { type: String, required: true },
  name: { type: String, required: true },
  parts: { type: [ChildSchema] },
});

const ParentModel = mongoose.model('Parent', ParentSchema);


export const getParents = async (): Promise<ExpectedParent[]> => {
  const parents = await ParentModel.find();
  return parents;  // TypeScript error here!
};

interface ExpectedParent {
  _id: string;
  name: string;
  parts: Array<{ _id: string; name: string }>;
}

I see the following error from TS:

Type '(Document<unknown, {}, { name: string; _id: string; parts: DocumentArray<{ name: string; }>; }> & { name: string; _id: string; parts: DocumentArray<{ name: string; }>; } & Required<...>)[]' is not assignable to type 'ExpectedParent[]'.
  Type 'Document<unknown, {}, { name: string; _id: string; parts: DocumentArray<{ name: string; }>; }> & { name: string; _id: string; parts: DocumentArray<{ name: string; }>; } & Required<...>' is not assignable to type 'ExpectedParent'.
    The types returned by 'parts.pop()' are incompatible between these types.
      Type '(Subdocument<ObjectId> & { name: string; }) | undefined' is not assignable to type '{ _id: string; name: string; } | undefined'.
        Type 'Subdocument<ObjectId> & { name: string; }' is not assignable to type '{ _id: string; name: string; } | undefined'.
          Type 'Subdocument<ObjectId> & { name: string; }' is not assignable to type '{ _id: string; name: string; }'.
            Types of property '_id' are incompatible.
              Type 'ObjectId | undefined' is not assignable to type 'string'.
                Type 'undefined' is not assignable to type 'string'.ts(2322)

Metadata

Metadata

Assignees

No one assigned

    Labels

    helpThis issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessaryhelp wanted

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions