Skip to content

Virtuals not included in the type from when toJSON is called #15316

Closed
@Tyler-Petrov

Description

@Tyler-Petrov

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.12.1

Node.js version

23.4.0

MongoDB server version

7.x

Typescript version (if applicable)

5.8.2

Description

I have a schema with a first name and a last name. I have a virtual that combines this values into one. I'm using this schema in SvelteKit, so the document needs to get sent over the wire using the .toJSON method. Shows the type of the schema's virtuals from the document, but after calling .toJSON({ virtuals: true }) the virtuals aren't on the type for the returned json. I can access the value just fine at runtime, but unfortunately it's not autocompleted.

Steps to Reproduce

import mongoose, { Schema } from "mongoose";

export const userSchema = new Schema(
    {
        Name: {
            type: {
                First: String,
                Middle: String,
                Last: {
                    type: String,
                    required: true
                }
            }, required: true
        },
    },
    {
        virtuals: {
            fullName: {
                get(): string {
                    const name = this.Name ?? {}
                    const fullName = []

                    if (name?.First) fullName.push(name.First);
                    if (name?.Middle) fullName.push(name.Middle);
                    if (name?.Last) fullName.push(name.Last);

                    return fullName.join(' ');
                },
                set(newValue: string) {
                    if (newValue == '') throw Error("Full Name must not be empty");

                    let newName = {}
                    const nameWords = newValue.split(' ')

                    if (nameWords.length == 1) {
                        newName = { Last: nameWords[0] }
                    } else if (nameWords.length == 2) {
                        newName = {
                            First: nameWords.at(0),
                            Last: nameWords.at(-1)
                        }
                    } else {
                        newName = {
                            First: nameWords.at(0),
                            Middle: nameWords.slice(1, nameWords.length),
                            Last: nameWords.at(-1)
                        }
                    }

                    this.set(newName);
                }
            }
        }
    }
);


const User = mongoose.model('User', userSchema, "User");

const user = await User.findOne()
if (user) {
    user.fullName
    //        ^? (property) fullName: string
    const userJSON = user.toJSON({ virtuals: true })
    userJSON.fullName
    //        ^? any
}

Expected Behavior

The expected behavior is for userJSON.fullName to be typed as a string. A possible solution would be to add another overload for .toJSON that adds the virtuals types to the document types. I'm not very handy at TypeScript, or I'd submit a pull request myself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    typescriptTypes or Types-test related issue / Pull Request

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions