javascript - No se pueden usar nuevos decoradores de ecmascript en typescript 2.4.2
Aquí está mi ejemplo de código:
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class A {
@enumerable(false)
a: number = 1
b: number = 2
myMethod () {}
}
const a = new A()
Lo que sea que intente, obtengo:
D:(real path removed)/first-try-typescript>tsc --emitDecoratorMetadata --experimentalDecorators decorators.ts
decorators.ts(8,3): error TS1240: Unable to resolve signature of property decorator when called as an expression.
He intentado todo, desde las sugerencias de las mismas preguntas en Stack Overflow:
- agregando emitDecoratorMetadata y experimentalDecorators a tsconfig
- ejecutando tsc --emitDecoratorMetadata --experimentalDecorators
- agregando
:anyal decorador de función para indicar el valor de retorno - añadiendo el tipo
descriptor: TypedPropertyDescriptor<any>
Siempre recibo este error. Tanto en una terminal como en las sugerencias de código de Webstorm. Decorador de método - lo mismo (ver ejemplo abajo).
function test(target: Object,
propertyKey: string,
descriptor: TypedPropertyDescriptor<any>): any {
return descriptor;
}
class A {
a: number = 1
b: number = 2
@test
myMethod () {}
}
const a = new A()
El código actualizado está aquí - https://github.com/rantiev/first-try-typescript
Respuesta #1
Desafortunadamente, los decoradores de propiedades no tienen acceso al descriptor de la propiedad, ya que las propiedades viven en la instancia de la clase, mientras que los decoradores se evalúan antes de que cualquier instancia pueda existir. Además, solo puedes usar la siguiente firma para un decorador de propiedad:
function (target: any, propKey: string | symbol)
Así que no hay descriptor aquí.
Tampoco puedes simplemente hacer Object.defineProperty(target, propKey.toString, { enumerable: false, value: ... }) porque eso se compartiría entre todas las instancias de tu clase, es decir, establecer una propiedad en una instancia se filtraría a otra.
Lograr lo que estás haciendo es posible, aunque un poco complicado. Lo que generalmente hago es crear un getter en el prototipo que cree el descriptor de propiedad deseado justo a tiempo. Algo así:
function enumerable(value: boolean) {
return function (target: any, propKey: string | symbol) {
Object.defineProperty(target, propKey, {
get: function () {
// In here, 'this' will refer to the class instance.
Object.defineProperty(this, propKey.toString(), {
value: undefined,
enumerable: value
});
},
set: function (setValue: any) {
// In here, 'this' will refer to the class instance.
Object.defineProperty(this, propKey.toString(), {
value: setValue,
enumerable: value
});
}
});
};
}
La funcionalidad de get/set "externa" solo se ejecutará una vez, ya que la propiedad de la instancia la eclipsará después de que el descriptor de la propiedad se haya creado en la instancia.
