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

Typescript: Type instantiation is excessively deep and possibly infinite #10189

Closed
mjfwebb opened this issue Apr 28, 2021 · 8 comments
Closed
Labels
typescript Types or Types-test related issue / Pull Request
Milestone

Comments

@mjfwebb
Copy link

mjfwebb commented Apr 28, 2021

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

After upgrading to use the new builtin types (previously using Mongoose version 5.10.9 and @types/mongoose": "^5.10.3) I am getting the error "Type instantiation is excessively deep and possibly infinite" on the following type of code:

return await Notification.find({ user: user._id }, 'message createdAt link').exec();

The User schema is quite large, but it's never been an issue before for me to find based on the recorded ObjectId this way.

If the current behavior is a bug, please provide the steps to reproduce.

Where the schema is like this:

import mongoose from 'mongoose';
import { IUser } from './user';

const NotificationSchema = new mongoose.Schema(
  {
    user: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true,
    },
    message: { type: String, required: true },
    link: { type: String, required: true },
  },
  {
    timestamps: true,
  },
);

export interface INotification extends mongoose.Document, mongoose.SchemaTimestampsConfig {
  user: IUser;
  message: string;
}

const Notification = mongoose.model<INotification>('Notification', NotificationSchema);
export default Notification;

tsconfig.json:

{
  "compilerOptions": {
    "target": "es2019",
    "module": "commonjs",
    "outDir": "dist",
    "strict": true,
    "alwaysStrict": true,
    "typeRoots": [
      "typings",
      "./node_modules/@types"
    ],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "removeComments": true,
  },
	"include": [
    "src/**/*",
    "typings"
	],
}

What is the expected behavior?

No Typescript error

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

Versions:
Node: v14.16.0
Mongoose: 5.12.6
MongoDB: 4.2.3
Typescript: 4.2.4

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

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

const NotificationSchema = new Schema(
  {
    user: {
      type: String,
      ref: 'User',
      required: true,
    },
    message: { type: String, required: true },
    link: { type: String, required: true },
  },
  {
    timestamps: true,
  },
);

export interface IUser extends Document {
    name: string
}

export interface INotification extends Document, SchemaTimestampsConfig {
  user: IUser;
  message: string;
}

const Notification = model<INotification>('Notification', NotificationSchema);

(async function() {

    await connect('mongodb://localhost:27017/test', {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useFindAndModify: false
    });

  await connection.dropDatabase();

  const entry = await Notification.create({user: 'Test', message: 'Hello', link: 'link'});
  entry.save();
  console.log('hello');
  return await Notification.find().exec();
  
  })();

@IslandRhythms IslandRhythms added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label May 4, 2021
@mjfwebb
Copy link
Author

mjfwebb commented May 7, 2021

@IslandRhythms Do the labels mean you cannot reproduce the problem and want me to try out your script? Or that you have been able to reproduce it but didn't remove the previous "can't reproduce" label?

@IslandRhythms
Copy link
Collaborator

I couldn't reproduce it. You can run the script and see if the problem reproduces for you, make adjustments to show how to get the bug to pop up. If you run this script and get the error, that means you have a problem with your setup

@vkarpov15 vkarpov15 removed the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label May 10, 2021
@vkarpov15
Copy link
Collaborator

@mjfwebb where does SchemaTimestampsConfig come from? Do you still have @types/mongoose installed? If so, you need to remove it.

@mjfwebb
Copy link
Author

mjfwebb commented May 11, 2021

@vkarpov15 SchemaTimestampsConfig is coming from mongoose according to what I can see: node_modules\mongoose\index.d.ts

Note the breadcrumbs at the top of this picture
image

I'm going to try with the repro script now.

@mjfwebb
Copy link
Author

mjfwebb commented May 11, 2021

I've managed to reproduce the problem in a new project.

I have a CodeSandbox example. but the code will need to be run elsewhere for the error to show (since CodeSandbox can't use mongoose.connect, or I am using the App incorrectly): https://codesandbox.io/s/infinte-depth-example-4dw9r

If needed I can upload the test project somewhere.

@IslandRhythms IslandRhythms added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. labels May 11, 2021
@vkarpov15 vkarpov15 added typescript Types or Types-test related issue / Pull Request and removed confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. labels May 16, 2021
@vkarpov15 vkarpov15 added this to the 5.12.10 milestone May 16, 2021
@vkarpov15
Copy link
Collaborator

Thanks for the repro script, we've confirmed that this is an issue and we found a couple of workarounds. The funny thing is that, if you remove 'fourth', everything works fine, so it isn't an infinite type recursion, just that we're hitting an arbitrary limit in TypeScript.

Specifically, this error is caused by Mongoose's UpdateQuery type and its use of @types/mongodb's OnlyFieldsOfType helper. Not sure why that particular helper causes this issue, we'll keep digging and see what else we can find.

However, we've managed to find a couple of workarounds. One workaround we've managed to find is to not use extends Document. Rewriting fourth.ts to the below works fine:

import { Schema, Document, model } from "mongoose";
  
const FourthSchema = new Schema({
  name: { type: String, required: true }
});

export interface IFourthSchema { // <-- remove `extends Document`
  name: string;
}

const Fourth = model<IFourthSchema>("Fourth", FourthSchema);
export default Fourth;

Based on our experience working with TypeScript so far, we recommend not using extends Document anymore, so this change isn't unreasonable.

Another workaround is to use PopulatedDoc<>. For example, below is a third.ts that compiles successfully:

import { Schema, Document, model, PopulatedDoc } from "mongoose";
import { IFourthSchema } from "./fourth";

const ThirdSchema = new Schema({
  name: { type: String, required: true },
  fourthSchemaObject: {
    type: Schema.Types.ObjectId,
    ref: "Fourth"
  }
});

export interface IThirdSchema extends Document {
  name: string;
  fourthSchemaObject: PopulatedDoc<IFourthSchema>; // <-- `fourthSchemaObject` can be either ObjectId or `FourthSchema` subdoc
}

const Third = model<IThirdSchema>("Third", ThirdSchema);
export default Third;

Which is how we recommend expressing populated docs in our soon-to-be released TypeScript populate docs (see #10212) .

@vkarpov15
Copy link
Collaborator

Fixed by allowing any for all update operators, which is something we've been meaning to do anyway.

@vkarpov15 vkarpov15 removed the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label May 16, 2021
3jins added a commit to 3jins/blog-renewal that referenced this issue Sep 20, 2021
- Fixed Mongoose Schema (Replace inheritance structure to intersection)
  Refer this: Automattic/mongoose#10189 (comment)
  and this: Automattic/mongoose#10212 (comment)
3jins added a commit to 3jins/blog-renewal that referenced this issue Nov 21, 2021
- Fixed Mongoose Schema (Replace inheritance structure to intersection)
  Refer this: Automattic/mongoose#10189 (comment)
  and this: Automattic/mongoose#10212 (comment)
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

3 participants