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

Integrate a fresh global JSX attribute into your React project without the need for @types in node_modules

It is crucial not to mention anything in tsconfig.json. Error Type '{ test: string; }' cannot be assigned to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'. Property 'test' does not exi ...

The TypeScript error message states that a value of 'undefined' cannot be assigned to a type that expects either a boolean, Connection

I've been grappling with this code snippet for a while now. It was originally written in JavaScript a few months back, but recently I decided to delve into TypeScript. However, I'm struggling to understand how data types are properly defined in T ...

Tips for correctly passing the appropriate data type using generics in TypeScript

If I have an array of objects with a key called render, which may be an optional function that takes a parameter (unknown type) const objectArray = [{a: 1}, {b: 2, render: renderFunction}, {c: 3, render: anotherFunction}] suppose the second object's ...

Tips for resolving the issue of dropdown menus not closing when clicking outside of them

I am currently working on an angular 5 project where the homepage consists of several components. One of the components, navbarComponent, includes a dropdown list feature. I want this dropdown list to automatically close when clicked outside of it. Here i ...

Take action once the Promise outside of the then block has been successfully completed

Presented below is the code snippet: function getPromise():Promise<any> { let p = new Promise<any>((resolve, reject) => { //some logical resolve(data); }); p.finally(()=>{ //I want do something when ou ...

The comparison between importing TypeScript and ES2015 modules

I am currently facing an issue with TypeScript not recognizing the "default export" of react. Previously, in my JavaScript files, I used: import React from 'react'; import ReactDOM from 'react-dom'; However, in TypeScript, I found tha ...

Discover the data type of the subfield within an interface or type in Typescript

Check out the interface and type declarations provided below: interface Foo { bar: { a: number b: string } } type Foo = { bar: { a: number b: string } } Is it possible to obtain the type definitions for "baz"? This will allow us ...

How can one change the data type specified in an interface in TypeScript?

I am currently diving into TypeScript and looking to integrate it into my React Native application. Imagine having a component structured like this: interface Props { name: string; onChangeText: (args: { name: string; value: string }) => void; s ...

Translate array into object with correct data types (type-specific method)

Welcome In our project, we have implemented attributes support where each attribute acts as a class. These attributes include information on type, optionality, and name. Instead of creating an interface for every entity, my goal is to automate this proces ...

The element is implicitly assigned an 'any' type due to the fact that an expression of type 'any' cannot be used to index types in nodejs and solidity

I am in need of setting networks in my contract using NodeJS and TypeScript. Below is the code I have written: let networkId: any = await global.web3.eth.net.getId(); let tetherData = await Tether.networks[networkId]; Unfortunately, I encountered ...

Is it possible to utilize Webpack 5's ChunkGroup API with several entries?

I am encountering an error message when attempting to upgrade from Webpack 4 to Webpack 5. The error states: Module.entryModule: Multiple entry modules are not supported by the deprecated API (Use the new ChunkGroup API) I have searched for information o ...

What is the method for defining a function within a TypeScript namespace?

Suppose there is a namespace specified in the file global.d.ts containing a function like this: declare namespace MY_NAMESPACE { function doSomething(): void } What would be the appropriate way to define and describe this function? ...

Using the decorator in VueJS Typescript allows you to easily define dynamic computed properties

On my hands is a component structured like this: @Component({ computed: { [this.stateModel]: { get() { return this.$store[this.stateModel]; } } } }) class Component extends Vue{ @Prop({ de ...

Creating valuable properties in TypeScript is a skill that requires knowledge and practice

In TypeScript, there is a unique feature available for defining properties with values using the `value` keyword. class Test { constructor(private value: number = 123) { } public MyValueProperty: number = 5; } Here is how you can define such ...

Angular Material (8) error code S2591: The variable 'require' is not defined in the current scope

Currently, I am attempting to record the date and time in the JavaScript console. Despite the code successfully logging the dates, an error message persists: Note: The code is functioning properly, with the dates being displayed in the console. It is only ...

In Javascript, check if an item exists by comparing it to null

I am working with a dropdown list that can be used for various types of data. Some of the data includes an isActive flag (a BOOLEAN) while others do not. When the flag is absent, I would like to display the dropdown item in black. However, if the flag exis ...

Offering a limited selection of generic type options in TypeScript

Is there a shorthand in TypeScript for specifying only some optional types for generic types? For example, let's say I have a class with optional types: class GenericClass<A extends Type1 = Type1, B extends Type2 = Type2, C extends Type3 = Type3> ...

How can we declare and showcase a generic object with an unspecified number and names of keys in React using TypeScript?

I am facing a challenge with objects that have a 'comments' field. While all the other fields in these different objects have the same types, the 'comment' field varies. I do not know the exact number or names of the keys that will be p ...

The issue of excessive recursion in Typescript

Currently, I am in the process of learning Typescript while working on some exercises. While attempting to solve a particular problem, I encountered an error related to excessive recursion. This issue arises even though I created wrapper functions. About ...

Can we guarantee the uniqueness of a function parameter value during compilation?

I have a set of static identifiers that I want to use to tag function calls. Instead of simply passing the identifiers as arguments, I would like to ensure that each identifier is unique and throws an error if the same identifier is passed more than once: ...