ExitDecorator in TypeScript

Introduction:

In my current setup, I have an object called `Item` that consists of an array of `Group(s)`, with each group containing an array of `User(s)`. The `Item` object exposes various APIs such as `addUser`, `removeUser`, `addGroup`, `removeGroup`, `addUnit`, and `removeUnit`. Every time one of these actions is taken, the `rank` property of each user within a certain group needs to be recalculated.

I am seeking a solution where the method `calcRank` is automatically triggered at the end of each API action without the need for explicit invocation. Something akin to an `OnExit` decorator would be ideal.

Answer №1

The Advice Design Pattern shows how to easily implement dynamic behavior in JavaScript:

function beforeAction(modifyBehavior) {
  return function(method) {
    return function beforeHandler(...args) {
      modifyBehavior.apply(this, args);
      return method.apply(this, args);
    };
  };
}

function afterAction(modifyBehavior) {
  return function(method) {
    return function afterHandler(...args) {
      const result = method.apply(this, args);
      modifyBehavior.apply(this, [args, result]);
      return result;
    };
  };
}

const defaultFunc = _ => _;

function applyAdvice({before: beforeModifier = defaultFunc, after: afterModifier = defaultFunc, skip: []}) {
  return function(Class) {
    Object.keys(Class.prototype).forEach(function(methodName) {
      if (!skip.contains(methodName)) {
        const method = Class.prototype[methodName];
        const afterDecorator = afterAction(afterModifier);
        const beforeDecorator = beforeAction(beforeModifier);
        Class.prototype[methodName] = afterDecorator(beforeDecorator(method));
      }
    });
  };
}


@applyAdvice({
  after() {
    this.updateRank();
  },
  skip: ['updateRank']
})
class Item {
  addUser() {}
  removeUser() {}
  addGroup() {}
  removeGroup() {}
  addUnit() {}
  removeUnit() {}
  updateRank() {}
}

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

Do not include ChangeDetectionStrategy when creating component

Is it possible to eliminate the default ChangeDetectionStrategy for each component creation? (Please note that I am working with Angular V 10 in a controlled environment for project maintenance) @Component({ xyz, changeDetection: ChangeDetectionStrategy. ...

Differences between TypeScript `[string]` and `string[]`

When using TypeScript, which option is the correct syntax? [string] vs string[] public searchOption: [string] = ['date']; public searchOption: string[] = ['date']; ...

Preventing JavaScript Compilation for a Specific Folder using tsconfig: A Step-by-Step Guide

To create my own npx package, I'm currently working on converting my .ts files into .js. The purpose of the application is to generate TypeScript templates for users based on their selected options. In this app, there's a CLI called 'index.t ...

How can Jest be configured to test for the "permission denied" error?

In my Jest test, I am testing the behavior when trying to start a node http server with an invalid path for the socket file: describe('On any platform', (): void => { it('throws an error when trying to start with an invalid socket P ...

Angular 4+ directive allowing interaction with the NgModel of a component

I'm looking to update styles based on the state of NgModel.control. To keep it DRY, I was thinking that a directive for reading the NgModel component state could be the solution. Is this actually feasible? I haven't been able to find any guidanc ...

Declaring properties for an interface

I've recently started using Typescript and I'm facing a problem with some interface props. There is an error message that says "Property 'services' does not exist on type 'IntrinsicAttributes & AkkordionProps[]", I'm confu ...

Refreshing the page causes the Angular/Ionic Singleton instance to be destroyed

I have a TypeScript singleton class that is responsible for storing the login credentials of a user. When I set these credentials on the login page and navigate to the next page using Angular Router.navigate (without passing any parameters), everything wor ...

After I deploy my Next.js code to Vercel, including Google Analytics added by @next/third-parties, I am encountering an error that does not appear in development mode

Lately, I completed a next.js project and integrated Google Analytics using @next/third-parties/google. During development, everything worked perfectly, but upon deploying it to vercel.com, an error popped up. ` ./app/layout.tsx:3 ...

During the present module, retrieve the runtime list of all modules that are directly imported (Javascript/Typescript)

Imagine you have a set of modules imported in the current module: import {A1, A2, A3} from "./ModuleA"; import {B1, B2, B3} from "./ModuleB"; import {C1, C2, C3} from "./ModuleC"; function retrieveListOfImportedModules() { // ...

Running a Jest test that triggers process.exit within an eternal setInterval loop with a latency of 0, all while utilizing Single

In the original project, there is a class that performs long-running tasks in separate processes on servers. These processes occasionally receive 'SIGINT' signals to stop, and I need to persist the state when this happens. To achieve this, I wrap ...

Tips for implementing multiple yield generators in redux-saga

Our redux-saga generator has multiple yield statements that return different results. I am struggling with typing them correctly. Here's an illustration: const addBusiness = function* addBusiness(action: AddBusinessActionReturnType): Generator< ...

Error encountered in NextJS API: "TypeError: res.status is not a function"

Background In my development environment, I am using NextJS v11.1.1-canary.11, React v17.0.2, and Typescript v4.3.5. To set up a basic API endpoint following the guidelines from NextJS Typescript documentation, I created a file named login.tsx in the pag ...

Within Angular, the Subscribe function is invoked after all other methods in the component have been executed. Consequently, this sequence of events often prevents me from effectively utilizing the response data

Struggling with implementing await and async in TypeScript, especially as a beginner. Below is how I attempted to use them: async refreshList(){ await this.service.refreshList().subscribe(res => { console.log(res); this.service.todoListModel=res; ...

Ways to immediately display an uploaded image as the background on a canvas

Using TypeScript, I am attempting to set an uploaded image as the background of a canvas. However, I am facing an issue where the image only loads properly after the user has uploaded it two times. How can I ensure that the image has finished loading befor ...

Error occurs when attempting to test both boolean and number data within an ngIf statement

In the scenario where I am working with a template that includes a boolean called readOnly and an array known as arrayOfStuff: <span *ngIf="!readOnly && arrayOfStuff && arrayOfStuff.length">Hey</span> When running eitherng bui ...

Is there a way to remove an event listener once the associated button has been clicked within the given code?

Is there a way to prevent this event from triggering once the "dispensed" button is clicked in another module? Here is the code snippet: stopDrugOrder(e: Event, drugOrder: any, drugName: string) { const confirmDialog = this.dialog.open(SharedConfirmat ...

Learn how to retrieve images from the web API at 'https://jsonplaceholder.typicode.com/photos' and showcase them on a webpage using Angular10

Using the API "https://jsonplaceholder.typicode.com/photos", I have access to 5 properties: albumId: 1 id: 1 thumbnailUrl: "https://via.placeholder.com/150/92c952" title: "accusamus beatae ad facilis cum similique qui sunt" url: "https://via.placeh ...

Error in Typescript Observable when using .startWith([])

I encountered the TypeScript error below: Error:(34, 20) TS2345: Argument of type 'undefined[]' is not assignable to parameter of type 'number | Scheduler'. Type 'undefined[]' is not assignable to type 'Scheduler& ...

Issue with const declaration in Typescript and Node.js - initializer is missing

Encountering a syntax error with the following line of code. Error message: SyntaxError: Missing initializer in const declaration const dataMap : Map<string, any> = new Map(); ...

Exploring Local Gems with Google Places API in Ionic 2

I recently integrated the Google Maps API into my app and now I am looking to incorporate Google Places as well. I have managed to successfully implement Geolocation, but I am facing difficulties when trying to perform a nearby search for "supermarkets" in ...