Get Off My Lawn Get Off My Lawn - 3 months ago 20
TypeScript Question

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?

Answer

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
    }
});