'TypeScript property decorator : access to other properties

I have a class Point like this :

class Point {
    @test('admin') x: number = 6

    y: number = 5
}

With Test decorator :

function test(myValue: string) {
    function t(target: Object, propertyKey: string, descriptor: 
    TypedPropertyDescriptor<any>) {
        //want to test y value > x value 
    }
return <any>t
}

In my test I want to check y value for exemple throw an error if x < y

Is it possible ?



Solution 1:[1]

You can't do it directly from the decorator function. You can, however, use the decorator function to redefine the getter and setter for the property, and access the context object passed into them from there:

class Point {
    @test() x: number;

    y: number;
    
    constructor(x: any, y: any) {
      this.y = y; // Doing this first since the test is on the x setter
      this.x = x;
    }
}

function test() {
  function t(target: Object, propertyKey: string) {
    //want to test y value > x value 
    Object.defineProperty(target, propertyKey, {
      set: function(this, newVal) {
        if (this.y > newVal)
          this._x = newVal;
        else
          throw new Error(`${this.y} is not greater than ${newVal}!`);
      },
      get: function() {
        return this._x;
      }
    });
  };
  return t;
}

try {
  let a = new Point(1, 2);
  console.log(`a = ${a.x}`);
}
catch (ex) {
  console.log(ex);
}

try {
  let b = new Point(3, 2);
  console.log(`b = ${b.x}`);
}
catch (ex) {
  console.log(ex);
}

TypescriptLang Snippet

Solution 2:[2]

No, according to the Typescript documentation, decorators are evaluated and called in the following order during object initialization:

  1. Parameter Decorators, followed by Method, Accessor, or Property Decorators are applied for each instance member. 2. Parameter Decorators, followed by Method, Accessor, or Property Decorators are applied for each static member. 3. Parameter Decorators are applied for the constructor. 4. Class Decorators are applied for the class.

The "complete guide" that they link to also elaborates on how this ties into the initialization of the object as a whole. In short, the constructor for the object (and by association your inline assignment of y = 3) has not yet been called by the time that @test('admin') is called. I've tested this locally and confirmed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 and0