Decorator used in identifying the superclass in Typescript

I am working with an abstract class that looks like this

export abstract class Foo {
  public f1() {
  }
}

and I have two classes that extend the base class

export class Boo extends Foo {
}

export class Moo extends Foo {
}

Recently, I created a custom decorator as shown below

export function Bla() {
  return (target: any, key: string, descriptor: PropertyDescriptor) => {
  }
}

Incorporating the decorator into my initial class now looks like this

export abstract class Foo {
 @Bla
 public f1() {
 }
}

I'm trying to figure out if there is a way in the decorator to distinguish where each call originated from, whether it was from Boo or Moo.

So far, I've attempted to check prototypes and constructors of target, but I haven't been able to determine the source class. Is there a method to achieve this or am I approaching it incorrectly?

Any help would be greatly appreciated.

Answer №1

If you want to access the method call itself, one way to do it is by inspecting the class instance:

function CustomFunction(target: any, propKey: string | symbol | d: PropertyDescriptor) {
  let originalMethod = target[propKey];

  // create a new property descriptor for the method, replacing the original one
  return {
    value: function () {
      let instance = this; 
      let classReference = instance.constructor; 

      if (classReference === CustomClass) {
        // perform actions specific to CustomClass
      }

      // call the original method
      return originalMethod.apply(this, arguments);
    }
  }
}

Answer №2

When you apply a decorator to a prototype method, it gets executed when the class containing the decorator is evaluated, not at a later stage when instances are created. The decoration is only applied to the prototype member of that particular class, and subclasses inherit the decorated member.

Consider the following example:

function Bla() {
  return (target: any, key: string, descriptor: PropertyDescriptor) => {
    console.log(target.constructor.name);
  }
}

abstract class Foo {
  @Bla()
  public f1() {
  }
}

// At this point, "Foo" will be displayed in the console

class Boo extends Foo {
}

class Moo extends Foo {
}

The decorator function will execute during the evaluation of class Foo, not when instances are created later on. You can observe this behavior by visiting the playground. If the following code comes after the class definitions mentioned above:

setTimeout(() => {
    new Boo; // No output in the console
    setTimeout(() => {
        new Moo; // No output in the console
        console.log("Done");
    }, 1000);
}, 1000);

If you were decorating an instance member, you could identify the instance as either a Boo or Moo, but distinguishing between them becomes challenging when decorating a prototype member.

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

Guide to verifying the upcoming behavior subject data in Angular 8

I am facing an issue where I am attempting to access the next value of a BehaviorSubject in multiple components using a service. Although I can display the value in the UI using {{ interpolation }}, I am unable to see it in the console.log. Can someone hel ...

TypeScript - create an Interface that must have either the error field or the payload field, but

My Action type has the following requirements: MUST have a field type {String} CAN include a field payload {Object<string, any>} CAN include a field error {Error} Constraints: IF it contains the field payload THEN it cannot contain the field er ...

Angular 9: Implementing a synchronous *ngFor loop within the HTML page

After receiving a list of subjects from the server, exercises are taken on each subject using the subject.id (from the server) and stored all together in the subEx variable. Classes are listed at the bottom. subjects:Subject[] temp:Exercise[] = [] s ...

Utilize variable as both a function and an instance of a class

Is there a way to access a variable as both a function and an object instance using TypeScript? log("something"); log.info("something"); I've attempted various methods, such as modifying the prototype, but nothing has proven succ ...

Issue with IntelliJ: TypeScript Reference Paths Are Not Relative

I am currently using IntelliJ as my IDE, but I am facing an issue with configuring gulp-typescript to compile my typescript code. The problem arises from the fact that IntelliJ does not treat my reference paths relatively, instead it references them from m ...

Are union types strictly enforced?

Is it expected for this to not work as intended? class Animal { } class Person { } type MyUnion = Number | Person; var list: Array<MyUnion> = [ "aaa", 2, new Animal() ]; // Is this supposed to fail? var x: MyUnion = "jjj"; // Should this actually ...

The propagation of onClick events in elements that overlap

Having two divs absolutely positioned overlapping, each containing an onClick handler. The issue is that only the top element's onClick handler fires when clicked. React 17 is being used. Here is some sample code: <div style={{ position: "abs ...

The server's response is unpredictable, causing Json.Parse to fail intermittently

I have encountered a strange issue that is really frustrating. It all started when I noticed that my Json.Parse function failed intermittently. Here is the code snippet in question: const Info = JSON.parse(response); this.onInfoUpdate(Info.InfoConfig[0]); ...

Issue in Angular: Attempting to access properties of undefined (specifically 'CustomHeaderComponent')

I have encountered a persistent error message while working on a new component for my project. Despite double-checking the injection code and ensuring that the module and component export logic are correct, I am unable to pinpoint the issue. custom-header ...

How can I access keys and values from an Observable within an Angular template?

Attempting to display all keys and values from an Observable obtained through Angular Firebase Firestore Collection. This is how I establish a connection to the collection and retrieve an Observable. The function is called subsequently. verOrden : any; ...

Removing a field from a collection using firebase-admin: Tips and tricks

I currently have a collection stored in Firebase Realtime Database structured like this: My requirement is to remove the first element (the one ending with Wt6J) from the database using firebase-admin. Below is the code snippet I tried, but it didn' ...

What causes an ObjectUnsubscribedError to be triggered when removing and then re-adding a child component in Angular?

Within a parent component, there is a list: items: SomeType; The values of this list are obtained from a service: this.someService.items$.subscribe(items => { this.items = items; }); At some point, the list is updated with new criteria: this.some ...

Best practices for implementing the map function with TypeScript

I'm currently working on mapping types in a DB using the Map function in JavaScript. This is my first time trying to do this, and I'm eager to learn but I've hit a roadblock. Here is the structure of the DB: const db = { data: [ { ...

Angular sets the required property only when the button is clicked

Is there a way to make a field required in Angular only when a button is clicked? Currently, the error message appears even before the user interacts with the field. I would like the error message "folder name is required" to only appear when the user cli ...

Display <video> component using Angular 2

When attempting to display videos sourced from an API link, I encountered a problem where only the player was visible without the actual video content. The navigation controls of the player were also unresponsive. Interestingly, when manually inputting the ...

How can I effectively address process.on test in TypeScript Mocha Testing with the help of a Sinon Spy?

I need to conduct a test on the warning process for my Typescript project. The specific code that I am attempting to test is shown below: process.on('warning', (warning) => { LoggingService.info('Warning, Message: ' + warning.mes ...

Obtaining JSON data in React Native without prior knowledge of the key

When I receive this type of data, the keys are common but the items vary. How can I extract and add this data to my list of categories? { "99": "Venues", "100": "Party Supplies", "101": "Enter ...

Can the WebSocket interface be substituted with WebSocket itself?

I'm currently in the process of setting up a WebSocket.Server using ws, Express 4, NodeJS, and TypeScript by following a guide. However, I've encountered an issue with the provided code not working as expected from the tutorial found at . In ord ...

What is the best way to retrieve every single element stored in an Object?

On a particular page, users can view the detailed information of their loans. I have implemented a decorator that retrieves values using the get() method. Specifically, there is a section for partial repayments which displays individual payment items, as d ...

What is the reason that property spreading is effective within Grid components but not in FormControl components?

Explore the sandbox environment here: https://codesandbox.io/s/agitated-ardinghelli-fnoj15?file=/src/temp4.tsx:0-1206. import { FormControl, FormControlProps, Grid, GridProps } from "@mui/material"; interface ICustomControlProps { gridProps?: ...