20

How to implement a typescript decorator? is a good example about how to use decorator in typescript.

Considering the below case,

class MyClass {
    @enumerable(false)
    get prop() {
        return true;
    }

    @property({required: true}) //here pass constant is no issue
    public startDateString:string;

    @property({afterDate: this.startDateString}) //how to pass startDateString here?
    public endDateString:string;
}

function enumerable(isEnumerable: boolean) {
    return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
        descriptor.enumerable = isEnumerable;
        return descriptor;
    };
}

I tried everything but it seems I have no way to pass startDateString into decorator argument. startDateString could be a variable, a function and a reference.

1
  • This might be possible depending on how and when you need to use the passed in value. I get it that you need to pass the... errrr... instance value of startDateString to the decorator applied to endDateString, but what are you planning to do with it in the decorator? Depending on circumstances, it is possible to get an instance member through a decorator. Commented Apr 13, 2016 at 17:32

2 Answers 2

21

What you are trying to do is not possible.

Decorators get called when the class is declared and at this time there is no instance to pass into the decorator.

For example, with this code:

class MyClass {
    startDateString: string;
    @property({ afterDate: this.startDateString })
    endDateString: string;
}
let myClass = new MyClass();
  1. MyClass is declared.
  2. The decorators are run on MyClass. There is no instance that exists to pass in at this point and this in the decorator argument refers to the global object—not an instance.
  3. new MyClass() is called and the instance is created. Decorators aren't called on this step. That already happened.

Take a look at the compiled JavaScript for reference:

var MyClass = (function () {
    // -- 1 --
    function MyClass() {
    }
    // -- 2 --
    __decorate([
        // see here... `this` is equal to the global object
        property({ afterDate: this.startDateString })
    ], MyClass.prototype, "endDateString", void 0);
    return MyClass;
})();
// -- 3 --
var myClass = new MyClass();

Note that using this.startDateString doesn't throw a compile error here because this is typed as any.

So what is trying to be done here by passing in an instance property doesn't make sense and isn't possible.

What you could do is make startDateString static then pass it in like so: @property({ afterDate: MyClass.startDateString }).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. But in my case, it cannot be static to be a class variable. It has to be an instance variable.
@new2cpp one thing you could do is pass in a string or a function that is passed an instance of the class and returns the property value. Something like { afterDate: "startDateString" } or {afterDate: (instance: MyClass) => instance.startDate }. You could then use this information later once you have an instance of the class to get the value out of the property. It's a hacky solution that's a great way to confuse everyone looking at the code though.
3

You can't access to a object property from a attribute definition.

Decorator is called when the property is defined.

You could use getter or setter to get control when access to the property.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.