In a previous post, we explored how to integrate TypeScript with your Mongoose models. In this post, we’ll move up to the service layer and see how we can use Mongoose types to get even more out of your application's Mongoose & Typescript implementations.
Firstly let’s answer some basic questions about the service layer: what is a service layer and how do I use it?
The service layer is used to encapsulate implementations of an application’s business logic and provide an API for invocation of that logic in a consistent way.
Services are functions that perform common tasks on your data, such as reading, writing, updating, and deleting. Services are often called by controllers or resolvers, and a single service is often used by several different functions.
This guide will include several different examples of code that lives inside a service layer. It will also include examples of code that uses the services. If you have used NestJS, the syntax used will look familiar. However, this guide is not about resolvers or services, it is about how you can use Mongoose’s types at the service layer.
To get started using Mongoose types, you will need to install the Mongoose package from DefinitelyTyped:
yarn add @types/mongoose -D
It’s common to have a service that is responsible for fetching data by a certain field, much like Mongoose’s
For example, an application that needs to find users by email addresses will benefit from having a service-level method for this task.
In this trivial example, we can simply type our input as the email address from the user model. This allows us to communicate with other developers where the data comes from and what its type is.
Note that if the email field is nullable on the user interface, the input will be nullable here too. This may be what you want, but it may also lead to some unexpected results.
What happens when the application requires a more generic, reusable method? We use Mongoose’s built-in types to tell the controller, or resolver what the method expects.
You’ll notice that
FilterQuery is a generic type that takes your
User type as a parameter. If you see an error here, make sure your
User interface extends
mongoose.Document. This is a common pattern that you will see throughout this guide.
Using options is just as easy with the `QueryFindBaseOptions` type.
In the above example, we included a default value for options, making the input optional.
Both of these usages are valid:
Another common practice is to combine the types from the object interface with the types from your model and the types from Mongoose can be combined to create services that meet your business logic requirements.
The above examples are trivial, but illustrate how you can use the Mongoose DefinitelyTyped package to make your services even easier to use and more reliable.
Strongly typed models with Mongoose and TypeScript: https://medium.com/@tomanagle/strongly-typed-models-with-mongoose-and-typescript-7bc2f7197722