Siddarth
Siddarth

Reputation: 33

Unable to access value using Property decorator in typescript

I am writing a Vanilla Typescript Program, as shown below

class DecoratorClass{
  @HelloWorld
  public property1:string="Siddu Rocks"
}
function HelloWorld(target:any,propertyName:string){
    console.log("The Class Target and prop names are:"+target[propertyName] + "," + 
                  propertyName)
}

I am getting the output as The Class Target and prop names are:undefined,property1 instead of The Class Target and prop names are: Siddu Rocks,property1

Why I am getting the property value as undefined, Is there anything I am missing here? I tried checking multiple blogs but no avail

Kindly help me

Upvotes: 0

Views: 2133

Answers (3)

Fahad Ali
Fahad Ali

Reputation: 39

function Min(limit:number){
return (target:Object,propertyKey:string) => {
    let value:string;
    console.log("Orignal Value ",target[propertyKey]); // undefined
    console.log("Original Value ", this[propertyKey]); //undefined
    const getter = function() {
        return value;
    }
    Object.defineProperty(target,propertyKey,{
        get:getter,
        set:function(newVal:string){
            if (newVal.length < limit) {
                let error:ValidationError = {
                    type: propertyKey,
                    message:`Your password must be greater than ${limit}`
                };
                let errors = this["errors"];
                console.log("ERRORS: ",errors);
                // Here I wanted to update the errors field, and I accessed it using this["errors"]. This will get all the errors and push the new error.
                errors.push(error);
                Object.defineProperty(target,"errors",{
                    value:errors
                })
            }else{
                value = newVal
            }
        }
    })
 }
}



type ValidationError = {
    type: string,
    message: string
}

class User {
    errors:ValidationError[] = [];
    @Min(8)
    password:string;

    @Min(7)
    username:string;
    constructor(password:string,username:string) {
        this.password = password;
        this.username = username;
    }
}

const user = new User("12345","fahad");
console.log(user.errors);

My output is following:

Orignal Value  undefined
Orignal Value  undefined
ERRORS:  []
ERRORS:  [
  { type: 'password', message: 'Your password must be greater than 8' }
]
[
  { type: 'password', message: 'Your password must be greater than 8' },
  { type: 'username', message: 'Your password must be greater than 7' }
]

Upvotes: -1

tenshi
tenshi

Reputation: 26327

A common misconception: target in the decorator is actually not an instance of the class, but the class prototype itself.

Also, the transpiled JavaScript actually looks something like this (even when using the ESNext target):

class DecoratorClass {
    constructor() {
        this.property1 = "Siddu Rocks";
    }
}

which is why when you attempt to log target[propertyName], gives you undefined. It's simply not declared on the class, but rather set when you create an instance of the class.

From the link above, there is also this note:

A Property Descriptor is not provided as an argument to a property decorator due to how property decorators are initialized in TypeScript. This is because there is currently no mechanism to describe an instance property when defining members of a prototype, and no way to observe or modify the initializer for a property. The return value is ignored too. As such, a property decorator can only be used to observe that a property of a specific name has been declared for a class.

Essentially, class decorators can only be used to modify the property (replace with getters/setters, observe changes to it, validate on change, etc).

Upvotes: 2

Matthieu Riegler
Matthieu Riegler

Reputation: 54658

Property decorators are modifying the class not the instance. So property1 is not set at the time HelloWorld is called.

Upvotes: 0

Related Questions