Mongoose: Official TypeScript definitions

Created on 28 Aug 2019  路  29Comments  路  Source: Automattic/mongoose

discussion enhancement

Most helpful comment

@vkarpov15 I would be very interested in helping with this and potentially taking point on maintaining this. I just finished a major refactor of the types currently in definitelytyped and have been trying to figure out how best to submit them. I am confident that @jloveridge will be interested in helping as we use mongoose with typescript at GradeCam and have for almost two years now.

If you're interested I'd like to discuss more directly with you sometime and see if we can get on the same page with what you'd like; there are a lot of things which could be improved by tying it together with mongoose itself because with some simple API changes (which could be optional) we could do a lot more with automatic type inference.

All 29 comments

I am about to open an issue regarding the fairly poor TS support, especially compared to the official Mongo client. Way too much use of any and not using generics well enough makes querying give no compile time support, say if a property name changes.

@kevinclarkadstech I'm sorry to hear about that. Can you provide some examples of code that's hard to write with TypeScript? Would be handy to have some concrete examples so we know where to start.

@vkarpov15 I would be very interested in helping with this and potentially taking point on maintaining this. I just finished a major refactor of the types currently in definitelytyped and have been trying to figure out how best to submit them. I am confident that @jloveridge will be interested in helping as we use mongoose with typescript at GradeCam and have for almost two years now.

If you're interested I'd like to discuss more directly with you sometime and see if we can get on the same page with what you'd like; there are a lot of things which could be improved by tying it together with mongoose itself because with some simple API changes (which could be optional) we could do a lot more with automatic type inference.

sure, say if I have a model:

interface Todo {
  done: boolean,
  text: string
}

type TodoDocument = Todo & Document;

const TodoModel: Model<TodoDocument> =...

when I say:

TodoModel.find({

I expect to get autocomplete/intellisense where conditions is a Partial which would give me type safety and autocomplete when saying:

{ _id: id }

or

{ done: false }

Because the TS definitions have any, there is no type safety or intellisense:

update(conditions: any, doc: any,
      callback?: (err: any, raw: any) => void): Query<any> & QueryHelpers;

@kevinclarkadstech I've got a pretty solid idea of how to fix that but haven't taken the time to do so yet even on my branch; my most recent additions (which I haven't tried yet to get merged to definitelytyped) will let you do a lean or .toObject and get back a Todo interface stripped of any functions your interface may have -- if you're interested in playing with it / helping me brainstorm on it shoot me an email [email protected] and I'll send you my local version and we can collaborate a bit while we wait for @vkarpov15 to decide how he wants to handle the official versions =]

@kevinclarkadstech one thing to consider when creating your search criteria, it isn't just as straightforward as saying {_id: id}. There are many other operations you can do such as: {_id: {$in: ids}}. I am not saying it is impossible but there will be a lot of complications in making search criteria "typesafe" without becoming overly restrictive.

[email protected]

Cool, I'll shoot you an email!

@kevinclarkadstech one thing to consider when creating your search criteria, it isn't just as straightforward as saying {_id: id}. There are many other operations you can do such as: {_id: {$in: ids}}. I am not saying it is impossible but there will be a _lot_ of complications in making search criteria "typesafe" without becoming overly restrictive.

Yeah, I think the official Mongo Db Node client does something like a union type of Partial | any so you get some intellisense but if you are adding any of the more advanced queries you get no intellisense but TS also does not complain either. Theirs are still not ideal because you still have to refer to the docs a lot.

Since Mongoose is already a wrapper around the Mongo Db queries, why not have some helper functions that translate input into Mongo Db query? Say my collection was based on interface

``` interface Todo {
id: string;
added: Date;
addedBy: string;
content: string;
done: boolean;
}

  Something like:

new Query().project(['id', 'content', 'done']).in({ 'addedBy': ['joe', 'fred'] }).eq({ done: false }).lt({ 'added': new Date() });

```

to get the id, content, done for users joe and fred where done is false and the added date is less than today.

I think that would make the ORM more useful than find(anything). Just my .02.

would be something like

class Query<Schema> {

  project(properties: keyof Schema[]): this {

  }

// Something like this, I can't remember how to write it
  in(propAndValue: { [keyof Schema: string]: typeof keyof Schema }): this {

  }

  lt( // same as above): this {

  }

}

Hey guys!

Have you ever tried typegoose?

I'm starting a new project which implements TypeScript, but having to define both the Mongoose model and the TypeScript interface is very annoying and error-prone.

I'm giving a shot to typegoose and it seems to be an excellent work.
I think it would be nice to join our efforts to make typegoose the main solution for mongoose TypeScript , what do you think?

Someone has any experience with typegoose to share?

Thanks!

@LucGranato I've tried typegoose, but stopped using it when I found out it doesn't do what @kevinclarkadstech is talking about. Prisma is the only project I know that is doing type-safe database access. It would be awesome if mongoose is able to provide the same level of type-safety, but I believe that's only possible by auto generating types based on the schema.

I've been chipping away at several approaches to this recently, and I've got the tricky part of deriving a typescript type from a schema configuration pojo working.

So far it works for numbers, strings, arrays, objects, and custom SchemaTypes. To make it a reality, though, it'll require a few compromises. So I wanted to ask if it'd be okay if:

  • Schema has an additional member that's similar to "obj" (currentConfigObject?), but it also tracks impure modifications to the schema through methods like "add" (shouldn't be hard to write).
  • to support custom SchemaTypes, we make a sacrificial property on SchemaType that's illegal to use for any other purpose other than mapping a schema type to its typescript type (e.g. UrlSchemaType.typescriptType: string).

...and actually... that seems to be it!

@vkarpov15 would you be open to Schema having a separate "obj" twin that stays up to date with changes to the schema?

If so, I'll continue down this approach and wrap it up (and update Model, Schema, find*, create, etc so that documents come out with all their types attached).

Actually, having a "obj" twin that's kept up-to-date will make #8207 not really needed either cause it can be a separate project.

Decided to throw it on gist:

https://gist.github.com/captaincaius/815d6d33141cd2d28458c6edef583054

LMK whether I should keep going on it...

We have a different method that we've been using which for us works extremely well; it uses decorators to basically define a class which doesn't actually get used directly but seems to (it's a little confusing at first, is the main drawback; it's actually very simple to use).

It's published here: https://github.com/gradecam/mongoose-decorators-ts

There are a number of improvements that we've made which haven't made it into that yet; I'm using it both at GradeCam and on hamstudy.org, a side project of mine, and it's been extremely helpful.

@taxilian interesting - it looks VERY similar to typegoose from the outside. I look forward to looking at the code when I have some time :).

Anyway what I'm suggesting would likely benefit mongoose-decorators-ts in addition to typegoose. For example, after you've got a model, newing up a document will have types on it. I'm not sure about mongoose-decorators-ts, but at least for typegoose it can offload some of the work that's kind of unclear where it should be maintained (i.e. mongoose maintains the relationship between mongoose schema definitions to types, and typegoose / mongoose-decorators-ts only worries about describing a mongoose schema definition using decorated classes).

@captaincaius I can definitely see why you might get that impression on first glance, but actually mongoose-decorators-ts actually defines the types as classes and then generates a schema from that which is actually what is used -- so the type you create with the class is actually the types that you are using; it therefore solves both problems in one definition.

That said, I do think there are a number of projects which could benefit from something like what you're doing; I've thought about it myself a few times; if I were to approach it I'd probably try to make js-schema (or whatever it is mongodb validation uses) work, but I haven't gotten far enough to validate the feasibility of that yet

What I miss the most (using vscode as code editor) is if a mongoose models use .methods or .statics methods, I can't go to definition, or find references. The only way is a code search

I'm using JS, and I'd like to just introduce some .d.ts or some comments to type those model methods. Without having to repeat myself/duplicate the schema props like in the comment in #8119

@caub that is the specific problem the mongoose鈥檚 decorators project I linked addresses

@kevinclarkadstech

when I say:

TodoModel.find({

I expect to get autocomplete/intellisense where conditions is a Partial which would give me type safety and autocomplete

A month ago or something before discovering typegoose and this thread I had the same thought and I started to work on this opensource project for mongo operators definitions.

It's still a work in progress, but it's something if you want to give it a try.

Here a screenshot that I took this morning when doing some updates:

image

My final goal was and still is to extend mongoose, which I typically use in my mongo-based projects, using declaration augmentation.

Those capabilities are already in the base mongo types.

I have forked the types from DefinitelyTyped to provide that and it's working great for me; this branch does have a few breaking changes which should be pretty self explanatory.

https://gist.github.com/taxilian/458ffdb9ce4ac402ca67adca43759987

Used with the MongooseDecorators project I linked above this provides everything I'm seeing anyone asking for here in a super lightweight way; it's a little confusing at first, but there is basically nothing extra at runtime other than a tiny bit of magic during the initialization.

The types linked above give you things like automatically pulling out the root type when you do a .lean() or .toObject and full smart types for update and filter queries

I noticed that:

  export function deleteModel(name: string | RegExp): Connection;

is missing from the declaration file in @types/mongoose.

The deleteModel function is present on the Connection class but not as a top level function of the module. It should be present at both locations just like modelNames.

@rnbrady this is not the @types/mongoose repo, so please open a bug here: https://github.com/DefinitelyTyped/DefinitelyTyped

Hi.
I just found ts-mongoose and it sounds promising. No decorators required.
Main repo: https://github.com/lstkz/ts-mongoose

Is mongoose support for typescript is released?

@ahmedbrandver Yes, it was released since v5.11.

Was this page helpful?
0 / 5 - 0 ratings