Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type of subdocument not inferred in toJSON() #14469

Closed
2 tasks done
richardsimko opened this issue Mar 27, 2024 · 2 comments · Fixed by #14526
Closed
2 tasks done

Type of subdocument not inferred in toJSON() #14469

richardsimko opened this issue Mar 27, 2024 · 2 comments · Fixed by #14526
Labels
typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@richardsimko
Copy link

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.2.3

Node.js version

latest

MongoDB server version

latest

Typescript version (if applicable)

5.4.3

Description

Following the example for subdocuments in TypeScript (https://mongoosejs.com/docs/typescript/subdocuments.html) the type of toJSON() isn't inferred on the subdocument.

Steps to Reproduce

The setup code is an exact copy from the docs, in the end are my tests.

import { Schema, model } from 'mongoose';

import type { Model, Types } from 'mongoose';
// Subdocument definition
interface Names {
  _id: Types.ObjectId;
  firstName: string;
}
// Document definition
interface User {
  names: Names[];
}

// TMethodsAndOverrides
type UserDocumentProps = {
  names: Types.DocumentArray<Names>;
};
type UserModelType = Model<User, {}, UserDocumentProps>;

const userSchema = new Schema<User, UserModelType>(
  {
    names: [new Schema<Names>({ firstName: String })],
  },
  { timestamps: true },
);

// Create model
const UserModel = model<User, UserModelType>('User', userSchema);


const doc = await UserModel.findOne({});
const jsonDoc = doc?.toJSON();
// Type string
jsonDoc?.names[0]?.firstName;
const jsonNames = doc?.names[0]?.toJSON();
// Type any
jsonNames?.firstName;

Expected Behavior

Since jsonDoc?.names[0]?.firstName is correctly inferred I would expect doc?.names[0]?.toJSON().firstName to also be correct.

@IslandRhythms IslandRhythms added the can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. label Apr 5, 2024
@IslandRhythms
Copy link
Collaborator

import { Schema, model, connect, connection } from 'mongoose';

import type { Model, Types } from 'mongoose';
// Subdocument definition
interface Names {
  _id: Types.ObjectId;
  firstName: string;
}
// Document definition
interface User {
  names: Names[];
}

// TMethodsAndOverrides
type UserDocumentProps = {
  names: Types.DocumentArray<Names>;
};
type UserModelType = Model<User, {}, UserDocumentProps>;

const userSchema = new Schema<User, UserModelType>(
  {
    names: [new Schema<Names>({ firstName: String })],
  },
  { timestamps: true },
);

// Create model
const UserModel = model<User, UserModelType>('User', userSchema);


async function run() {
  await connect('mongodb://localhost:27017');
  await connection.dropDatabase();
  await UserModel.create({
    names: [{ firstName: 'John'}]
  })
  const doc = await UserModel.findOne({});
  const jsonDoc = doc?.toJSON();
  // Type string
  console.log(jsonDoc?.names[0]?.firstName);
  const jsonNames = doc?.names[0]?.toJSON();
  // Type any
  console.log(jsonNames?.firstName);
  const name: string = jsonNames?.firstName;
  console.log('done');
}

run();

@richardsimko
Copy link
Author

I don't follow, of course you can assign jsonNames?.firstName to name, it has type any?

image

If you tweak your run() function like this:

async function run() {
  await connect('mongodb://localhost:27017');
  await connection.dropDatabase();
  await UserModel.create({
    names: [{ firstName: 'John' }],
  });
  const doc = await UserModel.findOne({});
  const jsonDoc = doc?.toJSON();
  // Type 'string | undefined' is not assignable to type 'boolean'
  const test: boolean = jsonDoc?.names[0]?.firstName;
  const jsonNames = doc?.names[0]?.toJSON();
  // No error
  const name: boolean = jsonNames?.firstName;
  console.log('done');
}

You'll see there is no error even though I'm trying to assign what should be a string to a boolean. I would expect both of those assignments to have the same error.

@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue typescript Types or Types-test related issue / Pull Request and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Apr 15, 2024
@vkarpov15 vkarpov15 added this to the 8.3.3 milestone Apr 15, 2024
vkarpov15 added a commit that referenced this issue Apr 15, 2024
@vkarpov15 vkarpov15 modified the milestones: 8.3.3, 8.3.2 Apr 16, 2024
vkarpov15 added a commit that referenced this issue Apr 16, 2024
types(DocumentArray): pass DocType generic to Document for correct toJSON() and toObject() return types
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typescript Types or Types-test related issue / Pull Request
Projects
None yet
3 participants