Issue with TypeScript Decorator Not Properly Overriding Get/Set Functions for Instance Properties

I'm struggling with creating a TypeScript decorator that modifies the get method for a property within a class. The issue I'm facing is getting it to affect instances of the class.

Below is an example scenario:

function CustomDecorator() {
    return function (target: Object, propertyKey: string) {
        Object.defineProperty(target, propertyKey, {
            get: function () {
                return 42;
            },
        });
    };
}

export class ExampleClass {
    @CustomDecorator()
    exampleProperty = 0;
}

const instance = new ExampleClass();
console.log(instance.exampleProperty);// Expected output is 42, but currently returns 0

If anyone could offer guidance or provide a solution, I would greatly appreciate it.

I've attempted replacing the target constructor with a new one that executes Object.defineProperty, however, this approach failed as well.

Answer №1

According to the official documentation, a property decorator is limited to observing the declaration of a specific property within a class, without the ability to modify its initial value.

The following JavaScript code demonstrates this concept:

class Foo {
    constructor() {
        this.bar = 0;
    }
}

To work around this limitation, one possible solution involves using a class decorator as shown below:

function Decorator() {
  return function (target: any) {
    return class extends target {
      bar = 42;
    };
  };
}

@Decorator()
class Foo {
  bar = 0;
}

const foo = new Foo();
console.log(foo.bar); // 42

If there is a need to specify the property key, a property decorator can be used to keep track of property keys like so:

const KEYS = Symbol('propertyKey');

function Decorator() {
  return function (Target: any) {
    return function () {
      const target = new Target();
      const keys = target[KEYS] || [];
      for (const key of keys) {
        target[key] = 42;
      }
      return target;
    } as typeof Target;
  };
}

function PropertyDecorator() {
  return function (target: any, propertyKey: string) {
    target[KEYS] = target[KEYS] || [];
    target[KEYS].push(propertyKey);
  };
}

@Decorator()
class Foo {
  @PropertyDecorator()
  bar = 0;

  baz = 0;
}

const foo = new Foo();
console.log(foo.bar); // 42
console.log(foo.baz); // 0

Answer №2

For the proper initialization of bar, it is essential to also define the setter method.

function Decorator() {
  return function (target: Object, propertyKey: string) {
    let value
    Object.defineProperty(target, propertyKey, {
      get: function () {
        return 42
      },

      // add
      set: function (v) {
        value = v
      },

    })
  }
}

Alternatively, bar can be defined as one of the following:

bar: undefined
bar: any

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

Angular Custom Pipe - Grouping by Substrings of Strings

In my Angular project, I developed a custom pipe that allows for grouping an array of objects based on a specific property: import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'groupBy'}) export class GroupByPipe impleme ...

Angular Material's dialog modal swiftly closes without delay

Could you please explain why the modal opens and then closes instantly when I click on the Create Project button? https://example.com/edit/angular-code I am trying to display a component within the modal using Angular Material. portafolio.component.ts ...

Is the communication between Angular service and component failing when using ngFor?

I am currently using Angular to create a video game page. When a specific title is clicked, the id is sent to make an API call with that specific id. I am able to retrieve the data in the selected-games component where I intend to use it, but when I use ng ...

Exploring the possibilities with Rollbar and TypeScript

Struggling with Rollbar and TypeScript, their documentation is about as clear as AWS's. I'm in the process of creating a reusable package based on Rollbar, utilizing the latest TS version (currently 4.2.4). Let's delve into some code snipp ...

crafting connections in 3D using TypeORM (ORM)

I attempted to construct a database schema involving users, groups, documents, and permissions. Users can be part of multiple groups Groups can have multiple users Users can possess permissions for documents Groups can have permissions for documents Perm ...

Directing users to varying pages based on a particular criteria

As we continue to develop our application, we are creating various pages and need to navigate between them. Our current framework is Next.js. The issue we are facing involves the Home page: when transitioning from the Home page to another page (such as pa ...

Retrieving the <html> tag within an Angular component

In an Angular component, the <body> and <head> tags can be accessed by injecting DOCUMENT as shown below: import { DOCUMENT } from '@angular/common'; import { Inject } from '@angular/core'; export class TestComponent { c ...

A guide on loading modules dynamically using React and Typescript from a server

I am working on a React / Typescript / Webpack / React-Router application that contains some large JS modules. Currently, I have two bundles (common.js and app.js) included on every page, with common.js being a CommonsChunkPlugin bundle. However, there is ...

Tips for implementing dynamic properties in TypeScript modeling

Is there a way to avoid using ts-ignore when using object properties referenced as strings in TypeScript? For example, if I have something like: const myList = ['aaa', 'bbb', 'ccc']; const appContext = {}; for (let i=0; i< ...

Eliminate the loading screen in Ionic 2

Within my app, there is a button that triggers the opening of WhatsApp and sends a sound. Attached to this button is a method that creates an Ionic loading component when clicked. The issue I am facing lies with the "loading.dismiss()" function. I want the ...

Angular auto suggest feature

I am working with a dropdown in Angular that contains JSON data. The data is stored in a List named options and I need to display the name field in the dropdown list. My current task involves implementing an autocomplete search feature for this dropdown. ...

A guide on retrieving the values of all child elements within an HTML element using Puppeteer

I have been exploring the capabilities of puppeteer and am trying to extract the values from the column names of a table. <tbody> <tr class="GridHeader" align="center" style="background-color:Black;"> <td cl ...

Step-by-step guide on invoking an asynchronous method in canActivate for Ionic and Angular

My objective is to acquire a token for authenticating users. I am utilizing the import { Storage } from '@ionic/storage-angular'; to store the data, but I am encountering an issue where the Storage methods only function in asynchronous mode. Her ...

Attach [!hidden] to a dropdown menu choice using Angular 2

How can I implement a show/hide feature for a select box in Angular 2+? Here's what I have so far: <select> <option disabled selected>Flow progress</option> <option *ngFor='let flow of flows'>{{flow}}< ...

The swipe motion will be executed two times

By pressing the Circle button, the Box will shift to the right and vanish from view. Further details (FW/tool version, etc.) react scss Typescript framer-motion import "./style.scss"; import React, { FunctionComponent, useState } from &q ...

Converting a JSON array stored in a local file to a TypeScript array within an Angular 5 project

I'm currently working on developing a web app using Angular 5. My JSON file has the following structure: [ { "id": 0, "title": "Some title" }, { "id": 1, "title": "Some title" }, ... ] The JSON file is store ...

Modify every audio mixer for Windows

Currently working on developing software for Windows using typescript. Looking to modify the audio being played on Windows by utilizing the mixer for individual applications similar to the built-in Windows audio mixer. Came across a plugin called win-audi ...

What is the best way to utilize the fresh Sanitizer API in Typescript?

Everything seems to be working well on Codepen, even without using window. It's surprising because I'm used to having to use window.x if ( 'Sanitizer' in window ) { console.log( 'sani', 'Sanitizer' in window ); } ...

Importing multiple modules in Typescript is a common practice

I need to include the 'express' module in my app. According to Mozilla's documentation, we should use the following code: import { Application }, * as Express from 'express' However, when using it in TypeScript and VSCode, I enc ...

Managing different data types in a single event emitter using Typescript: how do you approach it?

I'm currently working on a TypeScript function that detects the "Enter" key press and, if the event.target.value's length is greater than 0, redirects to a page with that value. This code snippet is being used in a Next.js application, hence the ...