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

InferSchemaType produces DocumentArray instead of a simple Array #13772

Open
2 tasks done
juona opened this issue Aug 23, 2023 · 6 comments
Open
2 tasks done

InferSchemaType produces DocumentArray instead of a simple Array #13772

juona opened this issue Aug 23, 2023 · 6 comments
Labels
typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@juona
Copy link

juona commented Aug 23, 2023

Prerequisites

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

Mongoose version

7.4.4

Node.js version

16.19.1

MongoDB server version

5

Typescript version (if applicable)

4.8.3

Description

The InferSchemaType utility converts subdocument arrays into DocumentArrays. My understanding is that this utility should produce a plain type that has nothing to do with Mongoose, so it should infer simple arrays instead of DocumentArrays. Is my expectation incorrect?

Possibly related: #12030 .

Steps to Reproduce

const mySchema = new Schema({
    nodes: {
        type: [
            new Schema({
                foo: String
            })
        ],
        required: true
    }
});

type IMySchema = InferSchemaType<typeof mySchema>;

Type IMySchema is:

type IMySchema = {
    nodes: Types.DocumentArray<{
        foo?: string | undefined;
    }>;
}

Expected Behavior

I'd expect type IMySchema to be:

type IMySchema = {
    nodes: Array<{
        foo?: string | undefined;
    }>;
}
@vkarpov15
Copy link
Collaborator

"My understanding is that this utility should produce a plain type that has nothing to do with Mongoose": Ideally yes, the Types.DocumentArray<> workaround is one exception to that rule. We're trying to change that for 8.0.

@vkarpov15
Copy link
Collaborator

As expected, going to be a bit hard to change this without #13856. Because InferSchemaType<> can't quite decide whether it wants to return the raw document type or the hydrated document type. And we don't want to do type transformations in HydratedDocument<> because of issues like #13523: mapping types in TypeScript get screwed up by generics, private fields, etc.

@benmeiri
Copy link

any workaround for this one?

@vkarpov15
Copy link
Collaborator

Not currently, we're working on a workaround.

@vkarpov15
Copy link
Collaborator

Going to move this out of 8.0 to a future release with the work we're doing on #13900. We haven't been able to make progress on this issue, and I don't want this to block 8.0 any further. Plus the work from #13900 is something we can release in a minor release.

@vkarpov15 vkarpov15 modified the milestones: 8.0, Parking Lot Sep 28, 2023
@FantinRaimbault
Copy link

FantinRaimbault commented Dec 14, 2023

My solution :

const likeSchema = new Schema(
    {
        userId: { type: String, required: true },
        date: { type: Date, required: true },
    },
    {
        timestamps: true,
        _id: true,
    }
);

const postSchema = new Schema(
    {
        title: { type: String, required: true },
        content: { type: String, required: true },
        likes: { type: [likeSchema], required: true, default: [] },
    },
    {
        timestamps: true,
        _id: true,
    }
);

const userSchema = new Schema(
    {
        _id: { type: mongoose.Schema.Types.ObjectId, required: true },
        name: { type: String, required: true },
        lastName: { type: String, required: true },
        settings: {
            type: {
                isPublic: { type: Boolean, required: true, default: false },
                isForSale: { type: Boolean, required: true, default: false },
            },
            required: true,
            default: {},
        },
        age: { type: Number, required: false },
        posts: {
            type: [postSchema],
            required: true,
            default: [],
        },
    },
    {
        timestamps: true,
        _id: true,
    }
);

 type ReplaceMongooseDocumentArrayByArray<MySchema extends Record<string, any>> = {
    [K in keyof MySchema]: MySchema[K] extends mongoose.Types.DocumentArray<infer ArrayType>
        ? ReplaceMongooseDocumentArrayByArray<Omit<ArrayType, keyof mongoose.Types.Subdocument>>[]
        : MySchema[K] extends number | string | boolean | Date | mongoose.Schema.Types.ObjectId | mongoose.Types.ObjectId
        ? MySchema[K]
        : ReplaceMongooseDocumentArrayByArray<MySchema[K]>;
};

type User = ReplaceMongooseDocumentArrayByArray<InferSchemaType<typeof userSchema>>;

vkarpov15 added a commit that referenced this issue May 15, 2024
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
Development

No branches or pull requests

4 participants