Using a Class Decorator in Typescript to Enhance Static Methods across all Classes

Imagine having a class filled with numerous static methods. The objective is to encapsulate each static method within a function. The specific aim is to handle async errors by applying .catch to every static method in the following manner:

// Within user-response.ts

const catchAsyncError = (func: Function) => {
  const catcher = (req: Request, res: Response, next: NextFunction) => {
    func(req, res, next).catch(next);
  }
  return catcher;
}

class UserResponse {
  static createUser = catchAsyncError(createUser);
  static updateUser = catchAsyncError(updateUser);
  static deleteUser = catchAsyncError(deleteUser);
  // more static methods...
}


// Inside routes.ts

const router = express.Router();

router.post('/create-user', UserResponse.createUser);
router.patch('/update-user', UserResponse.updateUser);
router.delete('/delete-user', UserResponse.deleteUser);

The main objective here is to eliminate redundancy in the code. Note how catchAsyncError(...) needs to be written repeatedly for each static method.

Additionally, the idea behind organizing these functions within a class is to provide some meaningful context to each function. This way, even a developer unfamiliar with the inner workings of the various user functions can understand their relationship by seeing UserResponse.createUser instead of just createUser.

A solution similar to the following is sought after:

// Within user-response.ts

const catchAsyncError = (func: Function) => {
  const catcher = (req: Request, res: Response, next: NextFunction) => {
    func(req, res, next).catch(next);
  }
  return catcher;
}

@withCatchAsyncError
class UserResponse {
  static createUser = createUser;
  static updateUser = updateUser;
  static deleteUser = deleteUser;
  // more static methods...
}

How does one implement such a solution? One can only hope it's achievable, as it presents a more elegant and visually pleasing approach compared to the previous one.

Answer №1

The withCatchAsyncError class decorator will dynamically access the class constructor during runtime without specific type information. It will iterate through the properties of the constructor, identifying any functions, and apply the catchAsyncError function to them. The process can be illustrated as follows:

function withCatchAsyncError(constructor: Function) {
  for (const key of Object.keys(constructor)) {
    if (typeof constructor[key] === 'function') {
      constructor[key] = catchAsyncError(constructor[key]);
    }
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The ng2-chart library displays date in the form of a Unix timestamp

I have a date object imported from my database, but it is showing up as a Unix timestamp (-62101391858000). I know I can format the date using pipes like {{myDate | date:medium}}, however, I am using ng2-charts so I need to find a different solution. My ch ...

Having trouble implementing the Material UI time picker because it does not meet the required DateTime format

REVISE I recently switched my dataType from DateTime to TimeSpan in my code. I have a functioning MVC version that already uses TimeSpan, and the times are posted in HH:MM format. Now, I am unsure if the issue lies with the headers set up on Axios or if it ...

Developing Angular PWAs with a focus on microfrontends

I have set up multiple microfrontends using an "app-shell" type of application for the domain root, with each microfrontend on the first path element. Each app is constructed as a standalone angular application utilizing shared libraries to reuse common co ...

Can a custom type guard be created to check if an array is empty?

There are various methods for creating a type guard to ensure that an array is not empty. An example of this can be found here, which works well when using noUncheckedIndexedAccess: type Indices<L extends number, T extends number[] = []> = T["le ...

Empty initial value for first item in array using React hooks

My goal is to store an array that I retrieve from an API in a useState hook, but the first entry in my array always ends up empty. The initial array looks like this: (3) ["", "5ea5d29230778c1cd47e02dd", "5ea5d2f430778c1cd47e02de"] The actual data I recei ...

What is the best way to retrieve body data in a Node.js Express application?

https://i.sstatic.net/3aGGI.png app.post('/hide_feed', middleware.authenticateToken, (req, res, next) => { if (req.body.followered_to_id) { return res.status(400).json({ status: 400, msg: req.body.followered ...

Encountering an error when trying to set data in a Firestore document with a customized JavaScript object: "Invalid data provided for function DocumentReference.set()"

For my initial project, I need help in identifying where the issue lies. Firstly, I have a function that adds data to Firebase: addpost() { let newposts = new Posts( this.addForm.value ) this.postsservice.addPosts(newposts); } Ne ...

Having trouble transitioning to Content Template Builder for Twilio WhatsApp integration

Recently, I've been transitioning to the new content template builder. First, here's the code snippet I was using previously: const message = await client.messages.create({ from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`, body: " ...

Why is TypeScript resorting to using 'any' for specific prop type definitions in React?

Having some trouble with my props typing: export interface ITouchable { isDisabled?: boolean; margin?: Margin; height?: number; bgColor?: string; } The definition of Margin is as follows: type Margin = | { top?: number; bottom?: nu ...

If you're setting up a new Next.js and Tailwind CSS application, you can use the flags -e or --example to start the project as a

After several attempts at creating a Next.js app with Tailwind CSS using JavaScript, I keep getting TypeScript files. How can I prevent this error? Despite following the usual commands for setting up a Next.js project, I am consistently ending up with Typ ...

Waiting for a function to complete its processing loop in Angular 7

In my code, I'm dealing with an angular entity called Z which has a property that is a list of another entity named Y. My goal is to delete the entity Z, but before doing so, I need to also delete all the Y entities within it. The challenge arises fro ...

Is there a way to set a default value for an Angular service provider?

Imagine an Angular Service that encapsulates the HTTP Client Module. export class HttpWrapperService { private apiKey: string; } Of course, it offers additional features that are not relevant here. Now I'm faced with the task of supplying HttpWr ...

SQL Query Fails Due to Variable Present

I've been working on a node.js application that interacts with a MySQL database using node-mysql for querying. Issue: I've encountered a problem where the query stops functioning properly when I use a variable for the table name. Am I overlookin ...

Output unprocessed HTML strings in EJS

Currently, I am implementing express.js with EJS templates and attempting to achieve the following: <%= "<a href='#'>Test</a>" %> Upon execution, it displays as follows: &lt;a href='#'&gt;Test&lt;/a& ...

The function service.foo is not recognized in Angular

My service function is not being recognized by my component import { Injectable } from '@angular/core'; import { ToastController } from '@ionic/angular'; @Injectable({ providedIn: 'root' }) export class LocationService { ...

Troubleshooting tip: Dealing with a blank screen when deploying a Node.js app on Heroku

After successfully working on localhost, I utilized webpack and babel before deploying the application. However, upon clicking the Heroku URL, the page appeared blank and index.html showed nothing. Here is a collection of Build Logs and Logs --tail: ----- ...

Encountering a module error when using SignalR with Webpack and TypeScript: 'Unable to locate module './NodeHttpClient''

I am currently working on integrating a SignalR client into an Angular application using Webpack and TypeScript. Here is the content of my package.json file: { "private": true, "version": "0.0.0", "scripts": { "test": "karma start ClientApp/tes ...

Exploring the directories: bundles, lib, lib-esm, and iife

As some libraries/frameworks prepare the application for publishing, they create a specific folder structure within the 'dist' directory including folders such as 'bundles', 'lib', 'lib-esm', and 'iife'. T ...

Guide to generating TypeScript output files within a non-hierarchical directory layout

In my project, I have a directory structure with multiple typescript files organized as follows: | src | app-1 | tsconfig.json | app-2 | tsconfig.json | common | standalone | tsconfig.json For each of the ...

Updates to TypeScript 2.3.1 creating disruptions in SystemJS plunk

Check out this official Angular + TypeScript plunk using SystemJS 0.19.31, now updated to TypeScript 2.3.0. However, changing the SystemJS configuration in the same plunk to TypeScript 2.3.1 or 2.3.2 'typescript': 'npm:<a href="/cdn-cgi ...