TS - decorator relies on another irrespective of their position within the class


Is it possible to consistently run function decorator @A before @B, regardless of their position within the class?


class Example {

@A()
public method1(): void { ... }

@B()
public method2(): void { ... }

@A()
public method3(): void { ... }

}

In the scenario above, I am seeking to ensure that the @A decorators for method1 and method3 are executed prior to @B() no matter where the methods are located in the class.

Answer №1

I discovered a clever technique using ReflectMetadata:

A special decorator


export const A =
  () =>
  (consumer: any, methodName: string, descriptor: PropertyDescriptor) => {
    const existingAMethods =
      Reflect.getOwnMetadata("A_METHODS", consumer.constructor) || []
    const options: {
      consumer,
      methodName,
      descriptor
    }
    existingAMethods.push(options)
    Reflect.defineMetadata(
      "A_METHODS",
      existingAMethods,
      consumer.constructor
    )
  }

Another unique decorator


export const B =
  () =>
  (consumer: any, methodName: string, descriptor: PropertyDescriptor) => {
    const existingBMethods =
      Reflect.getOwnMetadata("B_METHODS", consumer.constructor) || []
    const options: {
      consumer,
      methodName,
      descriptor
    }
    existingBMethods.push(options)
    Reflect.defineMetadata(
      "B_METHODS",
      existingBMethods,
      consumer.constructor
    )
  }

Introducing the final one called "C"

export const C = () =>
  (constructor: Function): void => {
    const options =
      Reflect.getOwnMetadata("A_METHODS", constructor) || []
    // Perform actions related to A
    const options =
      Reflect.getOwnMetadata("B_METHODS", constructor) || []
    // Perform actions related to B
  }

Application example

@C()
class Example {

  @A()
  public method1(): void { ... }

  @B()
  public method2(): void { ... }

  @A()
  public method3(): void { ... }

}

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

Exploring the best practices for utilizing the error prop and CSS with the Input API in Material UI while utilizing context

When working with the MUI Input API props and CSS, I encountered an issue related to the {error} and its use. This is how my code looks: const [value, setValue] = useState<string>(cell.value); const [startAdornment, setStartAdornment] = useState< ...

What causes @typescript-eslint to retain old types/files in its cache and prevent successful compilation?

When I kick off my Typescript application using tsc -b -w, I always encounter an issue with @typescript-eslint not reacting to file changes accurately. It flags invalid types/syntax errors where there are none. Restarting the process sometimes doesn't ...

Warning: Typescript is unable to locate the specified module, which may result

When it comes to importing an Icon, the following code is what I am currently using: import Icon from "!svg-react-loader?name=Icon!../images/svg/item-thumbnail.svg" When working in Visual Studio Code 1.25.1, a warning from tslint appears: [ts] Cannot ...

Sending the route path to the child component

<Route path="/pointandclick"> <MyComponent /> </Route> Is there a way for MyComponent to retrieve the path of the Route that was accessed in the code above? To clarify, if I want to determine the specific ...

Combining various POST requests by matching the common value in each array. (Angular)

Here are the two different sets of data: "statusCode": 200, "data": [ { "color": { "id": "1111", "name": null, "hex&quo ...

What is the best way to trigger a function in React when a constant value is updated?

In my React application, I have 3 components. The parent component and two child components named EziSchedule and EziTransaction. Each component fetches its own data from an API. The data to display in the EziTransaction child component depends on the reco ...

What are the steps to resolve warnings in an imported json file?

I am working on a Vue project where I have imported a JSON file into my TypeScript script using import jsonData from '@/assets/data1.json'; Although the data is accessible and functions correctly, I am encountering numerous warnings during the b ...

There was an unhandled exception that occurred due to a missing file or directory with the lstat error on 'D:a1s ode_modulesquill'

ngx-quill is causing issues in production, any suggestions? I am currently using "ngx-quill": "^13.4.0", but it is unable to find Quill on my server even though it works locally. The problem persists in the pipeline... An unhandled exception has occurred ...

What is the best way to access and read all @input elements within an Angular component?

Looking to retrieve all properties marked with the @Input() decorator in an Angular component. Attempts using reflect and reflect-metadata have been unsuccessful. Any suggestions on how to achieve this functionality? ...

Tips for creating a star program using Angular 2+

Create an Angular 2+ code snippet that will print asterisks (*) in a list on button click. When the button is clicked, it should add one more asterisk to the list each time. For example: Button Click 1 - Output: * Button Click 2 - Output: ** Button Cl ...

Nextjs introduces an innovative "OnThisDay" functionality, leveraging getServerSideProps and Date.now() to provide real-time information

I am currently working on adding an "OnThisDay" feature in my Nextjs project, inspired by Wikipedia's style of displaying events that happened on a specific date. To achieve this, I have implemented a function structured like the following code snippe ...

Exploring the intricacies of defining Vue component props in TypeScript using Vue.extend()

Here is a simple example to illustrate my question When I directly define my props inside the component, everything works fine <script lang="ts"> import Vue, { PropType } from "vue"; export default Vue.extend({ props: { col ...

What is the reason for a class's attributes being considered undefined even after they have been previously set?

Within my code, there is a class called WorkspaceDatabase that stems from the Dynamic Tree Example. I have incorporated some debugging information to gain a clearer understanding of the issue at hand. The Issue: Upon entering the complete() function, an ...

Postpone the initial click action triggered by the specified directive

Is it possible to create a directive that prompts for confirmation when a button is clicked? This would involve storing the original event and only executing it once the user confirms their choice. A similar behavior has been mocked here: https://stackbl ...

Is there a way to trigger validation with a disabled property?

My form element is set up like this: <input type="text" id="country" formControlName="Country" /> The form group looks like this: this.myForm = this.formbuilder.group({ 'Country': [{ value: this.user.Country, disabled: this.SomeProperty= ...

Exploring a different approach to utilizing Ant Design Table Columns and ColumnGroups

As per the demo on how Ant Design groups columns, tables from Ant Design are typically set up using the following structure, assuming that you have correctly predefined your columns and data: <Table columns={columns} dataSource={data} // .. ...

When the variable type is an interface, should generics be included in the implementation of the constructor?

Here is a code snippet for you to consider: //LINE 1 private result: Map<EventType<any>, number> = new HashMap<EventType<any>, number>(); //LINE 2 private result: Map<EventType<any>, number> = new HashMap(); When the ...

Angular 5 Dilemma: Exporting UI Components without Locating Template

My current project involves developing UI Components that will be used in various web projects within the company. Our plan is to publish these UI components as an npm package on our local repository, and so far, the publishing process has been successful. ...

What is the proper way to implement Firebase getDoc in Vue with vue-concurrency?

I am currently in the process of developing a TypeScript Vue composable that utilizes Firebase and the vue-concurrency library. According to the documentation, I need to explicitly type any intermediate values that are yielded. I am facing a challenge wh ...

Steps for configuring type definitions for an Apollo error response

Apollo's documentation explains that an error response can take the following form: { "data": { "getInt": 12, "getString": null }, "errors": [ { "message": "Failed to get s ...