Using a decorator with an abstract method

Discussing a specific class:

export abstract class CanDeactivateComponent {
  abstract canLeavePage(): boolean;
  abstract onPageLeave(): void;

  @someDecorator
  abstract canDeactivateBeforeUnload(): boolean;

}

An error occurred stating that

A decorator can only decorate a method implementation, not an overload
. While I understand that I cannot place a decorator in this scenario, is there a workaround to enforce the usage of @someDecorator before canDeactivateBeforeUnload in all implementations of this class? Is there a way to include this decorator directly in the abstract class itself to avoid repeated use in all implementations?

Your insights are appreciated!

Answer №1

Considering the situation, it might be beneficial to explore the option of utilizing a method that provides proxy functionality.

export abstract class CanExitComponent {
    abstract canLeavePage(): boolean;
    abstract onPageExit(): void;

    abstract canDeactivateBeforeUnload(): boolean;

    @someOtherDecorator
    _canDeactivateBeforeUnload(): boolean {
        return this.canDeactivateBeforeUnload()
    }
}

Answer №2

After finding inspiration from Rengers's response and apokryfos's input:

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}

example.ts:

#!/usr/bin/env ts-node

export function SomeDecorator(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor,
) {
  console.log('SomeDecorator was triggered');
}

export abstract class ExampleComponent {
  abstract _canDoTheThing(): boolean;

  @SomeDecorator
  canDoTheThing(): boolean {
    return this._canDoTheThing();
  }
}

class ExampleComponentImpl extends ExampleComponent {
  _canDoTheThing(): boolean {
    return true;
  }
}

new ExampleComponentImpl().canDoTheThing();
chmod u+x ./example.ts && ./example.ts

Result:

SomeDecorator was triggered

Answer №3

Do you know about method swizzling?

Method swizzling is a clever approach in object-oriented programming that enables us to modify or expand the functionality of a method by intercepting its original implementation and replacing it with a new one. It proves to be incredibly handy when we wish to include extra features, logging, or pre/post-processing to existing methods without altering the initial source code.

Let's explore an example in TypeScript where we showcase method swizzling by capturing the doSomething method of a parent abstract class and incorporating an additional action before executing the original implementation:

abstract class AbstractClass {
  abstract doSomething(): void;

  constructor() {
    const originalDoSomething = this.doSomething.bind(this);

    this.doSomething = function() {
      console.log('Performing additional action before doSomething');
      // Insert any additional logic here

      // Call the original implementation
      return originalDoSomething();
    };
  }
}

class MyClass extends AbstractClass {
  doSomething() {
    console.log('Original doSomething implementation');
    // Original doSomething logic here
  }
}

const myInstance = new MyClass();
myInstance.doSomething();

In this provided script, the AbstractClass contains an abstract method called doSomething. The method swizzling process takes place within the constructor of AbstractClass. We retain the original implementation of doSomething in originalDoSomething and then set a new wrapper function to this.doSomething, which executes the additional action prior to calling the original implementation.

The MyClass class inherits from AbstractClass and includes its own version of the doSomething method.

To conclude, we initiate an instance of MyClass and trigger the doSomething method. Consequently, the swizzling mechanism defined in the AbstractClass constructor comes into play, running both the added action and the original implementation.

Feel free to adapt the logging and extra action logic as per your specific needs. Method swizzling provides tremendous flexibility in enhancing existing methods while preserving the cleanliness and manageability of the codebase.

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

Transmit a sequence of keys to the web browser

I'm having difficulty in sending a Shift key command followed immediately by tilde (~). I've attempted various examples, and here's one that I'm currently working on. I am testing the following scenario - selecting a specific image, t ...

The Generic Function's Return Type in Typescript

The latest addition of ReturnType in TypeScript 2.8 is a highly valuable feature that enables you to capture the return type of a specific function. function foo(e: number): number { return e; } type fooReturn = ReturnType<typeof foo>; // numbe ...

Merging RXJS observable outputs into a single result

In my database, I have two nodes set up: users: {user1: {uid: 'user1', name: "John"}, user2: {uid: 'user2', name: "Mario"}} homework: {user1: {homeworkAnswer: "Sample answer"}} Some users may or may not have homework assigned to them. ...

What is the equivalent of defining conditional string types in Typescript similar to flow?

type UpsertMode = | 'add' | 'update' | 'delete'; interface IUpsertMembers { mode: UpsertMode; } const MagicButton = ({ mode: UpsertMode }) => { return ( <button>{UpsertMode}</button> ); } const Upse ...

Next.js v13 and Firebase are encountering a CORS policy error which is blocking access to the site.webmanifest file

Background: I am currently developing a website using Next.js version 13 in combination with Firebase, and I have successfully deployed it on Vercel. Upon inspecting the console, I came across two CORS policy errors specifically related to my site.webmani ...

How to use TypeScript variables in React applications

In my current project, I am attempting to customize a Fabric JS component (Dropdown) using styled-components within a React component. The specific CSS class names are defined in a file located at office-ui-fabric-react/lib/components/Dropdown/Dropdown.sc ...

The combination of Observable streams in combineLatest will persist even if one encounters a

I have a function designed to retrieve multiple documents from Firebase. fetchDocuments(documentIds: string[]): Observable<TreeNodeDocument[]> { const observables = []; for(let id of documentIds){ observables.push(this.fetchDocument( ...

The error message states that the property 'registerUser' is not found on the class 'UserController'

In the controller file, I exported two functions (registerUser and loginUser) as default. No errors were thrown at that stage, but when attempting to access the routes, an error occurred stating - Property 'registerUser' does not exist on type &a ...

Using external URLs with added tracking parameters in Ionic 2

I am looking to create a unique http link to an external URL, extracted from my JSON data, within the detail pages of my app. Currently, I have the inappbrowser plugin installed that functions with a static URL directing to apple.com. However, I would lik ...

Utilizing asynchronous JavaScript imports within exported classes

Currently, I have a package with async/dynamic exports that I import in the following manner: (async function() { const libEd = await import("../../.cache/ed25519wars/index.js"); })(); I plan to re-expose certain functions from libEd within a class str ...

Precisely outline the function type that operates on an object, makes changes to its values, and then outputs the object in TypeScript

Can anyone help me create a function that generates a new object with the same keys as the input object, but with all values set to null? Here's the existing code: function nullify(arg) { var returnObj = {} for (var key in arg) { returnObj[ ...

Error TS2322 occurs during compilation in Typescript when using ng.IPromise

Having some issues while using Angular 1.x with Typescript. Here is the code causing trouble: get(id): ng.IPromise<Server.MyItem> { return this.$http.get(`${this.baseAddress}/${id}`).then(d => d.data); } After compiling with tsc, I am encoun ...

Creating a personalized connect function in Typescript for react-redux applications

Currently, I am in the process of migrating a large and intricate application to Typescript. One specific challenge we are facing is our reliance on createProvider and the storeKey option for linking our containers to the store. With over 100 containers in ...

React app version displaying incorrect links to CSS and JS files

I have been immersed in a React project called Simple-portfolio, you can find the GitHub repository here: https://github.com/Devang47/simple-portfolio and the live site at this URL: While everything works smoothly on the development server, I encountered ...

Troubleshooting Paths with Angular's NgFor Directive

Within my Angular project, I have implemented a basic ngFor loop to display logo images. Here is a snippet of the code: <div *ngFor="let item of list" class="logo-wrapper"> <div class="customer-logo"> & ...

Ensuring consistency between TypeScript .d.ts and .js files

When working with these definitions: https://github.com/borisyankov/DefinitelyTyped If I am using angularJS 1.3.14, how can I be certain that there is a correct definition for that specific version of Angular? How can I ensure that the DefinitelyTyped *. ...

Using an external variable within an internal function in TypeScript

I am facing a situation where I have a variable outside of a function that needs to be updated, but I am unable to access it using "this" as it is not reachable at that point in the code. export class GamesDetailPage { details : any = {}; type : St ...

What steps should be taken to enable SCSS in Jest for unit testing in TypeScript Next.js?

I am facing an issue with the scss import in my project. I have attempted to solve it by using mockup and identity-obj-proxy, but neither of them seems to work. I suspect that there might be a problem with my regex expression. The specific error arises fr ...

What is the best way to inform TypeScript when my Type has been altered or narrowed down?

In my application, I have a class that contains the API code: export class Api { ... static requestData = async ( abortController: React.MutableRefObject<AbortController | null> ) => { // If previous request exists, cancel it if ...

redux-toolkit extraReducers not triggering

I've been experimenting with createAsyncThunk, but I'm having trouble getting the extraReducers to trigger. This is what my current setup looks like: export const getAllAgents = createAsyncThunk( "getAllAgents", async (token: string ...