Skip to content

mongoose typescript models

chaser92 edited this page Jul 21, 2014 · 7 revisions

Creating Mongoose models with TypeScript

If you're developing a project in TypeScript, it seems natural to expect that all models you use are strongly-typed. On the other side, you may often need to have them loosely coupled to the backend - for example to share them between client and server or multiple applications. There is a way to design your models so that they are interchangeable when needed, yet useful when you need full-fledged Mongoose ORM functionality.

Designing a POJO interface

For this guide, we'll want to design an User model. Let's start with creating the POJO interface for all User objects:

interface IUser {
	email: string;
	password: string;
	displayName: string;
};

export = IUser;

I'll refer to this file further as IUser.ts.

Adding Mongoose functionality

Declaring POJO and Mongoose mixin

In a separate file, we'll want to enable Mongoose ORM management for all User objects. To do so, we'll need to declare a mixin of our IUser and mongoose.Document - the latter interface contains ORM-based functions such as save().

import mongoose = require("mongoose");

import IUser = require("../../shared/Users/IUser");

interface IUserModel extends IUser, mongoose.Document { }
```

This `IUserModel` now can be passed as a type argument for Mongoose's model function. But first…

### Declaring Mongoose schema for `User` ###

This is needed, even though it seems like it's redundant - TypeScript does not preserve runtime type information, so it's lost in the transpiling phase. On the other hand, the object model in a database does not need to match an in-memory representation exactly - we may want to add some other, "technical" properties.
So now let's declare our schema:

var userSchema = new mongoose.Schema({ email: String, password: String, displayName: String });


### Wrapping it up together with `Model` ###

Now that we've got all parts together, we'll want to have an actual implementation of our interface. Fortunately, all we have to do is call the `mongoose.model<T>` method, passing the schema. Please note that the `T` type argument must derive from `mongoose.Document` - that's why we'll pass our mixin:

var User = mongoose.model("User", userSchema);


And this is what we're going to export.

export = User;


Let's save this file as `User.ts`.

## Using the model in server code ##

The model that we have just designed can be used just like any other Mongoose model. All we have to do is load our `User.ts` file:

import User = require("./User");

var user = new User({email: "[email protected]"}); user.save();


This `user` variable implements the `IUser` interface and can be used in all functions, that previously referred to our POJO objects.

function doSthWithUser(user: IUser) { }

doSthWithUser(user); // works!


## Using model in client-side TypeScript ##

We can pass our object to client (e.g. serialized using JSON) using model's `toJSON()` method. The receiver callback on client-side should then validate the object (or assume it's compliant with the schema), and then cast it to desired POJO type (`IUser`). Note that casting itself does not imply any type-checking.
Clone this wiki locally