Enhancing Express.js Requests with TypeScript: Adding User Objects and More

Express JS has been one of the best Node JS framework for creating backend(server side) part of any application. It is fast and easy to learn and implement. It is soo scalable and reliable that it is being used in small and as well as in large application.

I loved using it along with typescript too because it enhances the code quality and readability. In addition, you also get the advantage of better code completion and intellisense when using modern text editors like Visual Studio Code.

One of the most useful concept of Typescript is “Declaration Merging”.
Declaration Merging allows you to merge two or more distinct declaration or types declared with the same name into a single definition. This concept allows you to attach your own custom property onto another Typescript interface type.

Lets take a look at Express middleware.

The above code is an Express middleware that is used to ensure that a user is authenticated when he or she tries to access a protected resource.
It decodes the user’s token from the authorization property of the request headers and attaches the current user to the Request object. But as we can the red line is indiacating an error, thats because, the property currentUser does not exist on Express's Request interface type.

To fix this, first we need to create a new type declaration for the express request object.

Let’s create a folder for this new declaration
  • inside ‘src’ folder create ‘@types’ folder.
  • inside ‘@types’ folder, create ‘express’ folder.
  • inside ‘express’ folder create ‘index.d.ts’ file.
  • like this, src > @types > express > index.d.ts




You would notice this is the exact same file name and path in our node_modules/@types folder. For Typescript declaration merging to work, the file name and its path must match the original declaration file and path.

Next we need to make some few changes in the project’s tsconfig.json file. Let's update the typeRoots value to the following:
  ...
    "typeRoots": [
      "@types",
      "./node_modules/@types",
    ]                    
  ...
    


By default, the Typescript compiler looks for type definitions in the node_modules/@types folder. The above code instructs the compiler to look for type definitions in this folder as well as our custom @types folder in our project root.

Now it’s time to add our custom currentUser property to Express's Request interface type by modifying the index.d.ts file we created earlier:


  import { IUserModel } from "../../models/userModel";

  declare global{
    namespace Express{
      interface Request{
        currentUser: IUserModel;
        /*
          other variables (if needed)
        */
      }
    }
  }
    


Lets take a look again at our middleware file and we immediately notice that the red line is gone! This is because the Typescript compiler now recognizes the currentUser property as a valid property on the Request type interface.

Congrats, we successfully performed a type declaration for oue user property

Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. Awesome. Thanks for putting this together.
    Do you know of a way to use declaration merging to replace existing methods. E.g replace Express.Response.status() so that it takes a different type of argument or it returns void?

    I tried this by following your approach, declaring my own Response interface and then trying to define the status method to return void. I know this has not worked because I am still able to chain other response methods after a call to status()

    How can I solve this?

    ReplyDelete

Post a Comment

Popular posts from this blog

Custom Validator to match Password and Confirm Password in Angular

How to Avoid Page Changes When You Have Unsaved Changes in Angular