Get Off My Lawn
Get Off My Lawn

Reputation: 36311

set information about a property

I am making an editor that will look at javascript classes (es6), and display particular information about key properties. I wanted to try and use decorators to accomplish this, so something like this:

class Transform extends Component {

    @serializable
    public position: Vector3 = Vector3.zero;

}

Then my decorator would looks something like this:

function serializable(...args): any {
    let target = args[0];
    let key = args[1];
    let descriptor = args[2] || {};
    descriptor.writable = true;
    descriptor.serializable = true;
    return descriptor;
}

Then when I am analyzing the class I would do something like this:

components.forEach(comp => {
    var info = Object.getOwnPropertyDescriptor(comp, 'position');
    if(info.serializable){
        // display in editor
    }
});

The issue I am having is that it will let me set additional descriptor values, but I can not access them.

What could I do to accomplish this?

Upvotes: 0

Views: 67

Answers (1)

Nitzan Tomer
Nitzan Tomer

Reputation: 164147

I have to admit that it's not very clear from the documentation, because it states that:

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. As such, a property decorator can only be used to observe that a property of a specific name has been declared for a class.

But then:

If the property decorator returns a value, it will be used as the Property Descriptor for the member

So my understand was that while the function doesn't get the descriptor to change, it can "change it" by returning a descriptor like you did.
But I guess that this isn't the case as it doesn't work.

However, just below that it gives an example of how to do that using reflect-metadata:

import "reflect-metadata";

const serializableMetadataKey = "serializable";

function serializable(): any {
    return Reflect.metadata(serializableMetadataKey, true);
}

function isSerializable(target: any, propertyKey: string) {
    return Reflect.getMetadata(serializableMetadataKey, target, propertyKey);
}

class Transform extends Component {
    @serializable()
    public position: Vector3 = Vector3.zero;
}

components.forEach(comp => {
    if (isSerializable(comp, "position")) {
        // display in editor
    }
});

Upvotes: 1

Related Questions