Skip to main content

Polymorphism By Example, A Deeper Dive πŸ€”

In the realm of JavaScript and TypeScript, polymorphism can be observed in several libraries and frameworks. One such library is Express.js, a minimalist web framework for Node.js.

The beauty of polymorphism in Express.js can be particularly appreciated in the use of middleware functions.

The Magic of Middleware​

Middleware functions are functions that have access to the request object, the response object, and the next function in the application’s request-response cycle. Middleware functions can perform a variety of tasks, including executing any code, making changes to the request and response objects, ending the request-response cycle, and invoking the next middleware in the stack.

Understanding Request, Response, and NextFunction​

In Express.js with TypeScript, Request, Response, and NextFunction are interfaces provided by the Express.js type definitions.

  • Request: Represents the HTTP request, with properties for the request query string, parameters, body, HTTP headers, and more.
  • Response: Represents the HTTP response that an Express app sends when it gets an HTTP request. It has methods to send the HTTP response, like res.send(), res.json(), res.sendFile(), and more.
  • NextFunction: Represents the next function, which you call to pass control to the next middleware function.

Express.js Middleware: A Playground for Polymorphism​

The use of middleware in Express.js is a prime example of polymorphism in action. Middleware functions, despite their internal differences, all adhere to the same interface. They accept Request, Response, and NextFunction parameters, which means they can be used interchangeably in an Express.js application's middleware stack.

Let's look at a simple example:

import express, { Request, Response, NextFunction } from "express";

const app = express();

const middleware1 = (req: Request, res: Response, next: NextFunction) => {
console.log("Middleware 1");

const middleware2 = (req: Request, res: Response, next: NextFunction) => {
console.log("Middleware 2");


app.listen(3000, () => {
console.log("Server started");

In this code snippet, middleware1 and middleware2 are different functions but can both be used as middleware in the Express.js application because they follow the same interface. This is a manifestation of polymorphism, as different middleware functions can be used interchangeably in the application's middleware stack.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.


The Power of Polymorphism​

Polymorphism is a powerful concept that promotes flexibility and consistency. With polymorphism, you can handle different objects in a similar manner, allowing for more general and abstract implementations. This ability to "change forms" brings several benefits.

  1. Code Reusability: Polymorphism promotes code reusability by allowing you to write code that can work with objects of different types. Instead of writing separate functions for each object type, you can write a single function that takes an object of a super type. This function can then be used with any subtype of that super type. For instance, in an Express.js application, a single middleware function can process various types of HTTP requests (GET, POST, DELETE, etc.), enhancing the reusability of the code.

  2. Interface Consistency: By using polymorphism, you can maintain a consistent interface across different types of objects. This consistency makes it easier to understand and use the system. In the context of Express.js, all middleware functions use the same interface (i.e., they take the same parameters: Request, Response, and NextFunction). This consistency simplifies the process of adding new middleware functions to the application, as developers can predict the interface they need to adhere to.

  3. Flexibility: Polymorphism provides flexibility in programming by enabling you to introduce new object types that adhere to a specific interface without modifying the overall system. In Express.js, for example, you can effortlessly add new middleware functions to perform new tasks. As long as the new functions follow the standard middleware interface, the existing system does not need to be changed. This flexibility is crucial for growing and evolving applications, as it allows for the seamless integration of new features and enhancements.

  4. Robustness: Polymorphism makes your application more robust by allowing it to handle a wider variety of situations. For example, middleware functions in Express.js can perform a wide range of tasks, including logging, request validation, authentication, and more.

  5. Scalability: As your application grows, you may need to introduce new types of objects. With polymorphism, you can easily introduce new types without having to rewrite existing functions or methods.

  6. Reduced Complexity: Polymorphism can help to reduce complexity in large codebases. By treating different objects as instances of a common super type, you can write more straightforward code that's easier to understand and maintain.

By understanding and utilizing polymorphism, you can reap these benefits and write code that is more flexible, robust, scalable, and easier to maintain. The Express.js middleware system is a great example of how polymorphism can be put into practice in a real-world application.

What Can You Do Next πŸ™πŸ˜Šβ€‹

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for software developers.

YouTube @cloudaffle