Búsqueda de sitios web

typescript1.5 - TypeScript 1.5, reflexión y decorador


Me preguntaba si era posible usar reflexión, y más particularmente reflexión de clase con respecto a un decorador, en una propiedad, en un parámetro o en un método?

¿Es posible usar un reflector para obtener la información utilizada en los decoradores?

Si es posible, ¿cómo podemos hacer eso? Si no, ¿por qué no podemos hacer eso?

EDITAR :

Tengo una aplicación en la que uso decoradores, para inyectar datos, desde un serviceRegistry, a un decorador llamado @Inject.

En esta aplicación, lleno un registro de servicios simple a mano, como:

serviceRegistry.push(MyClass1)
serviceRegistry.push(MyClass2)
...
serviceRegistry.push(MyClass100)

El objetivo es poder llenar este registro de servicios con clases que estén decoradas con la anotación @ToInject, en tiempo de ejecución.

Esto me permitirá evitar llenar este registro a mano y automatizar esto de manera sencilla.

Gracias de antemano

Respuesta #1

Puedes usar la reflexión importando el paquete reflect-metadata.

import 'reflect-metadata';

Úsalo con TypeScript 1.5 y la bandera del compilador emitDecoratorMetadata configurada en true. No olvides incluir también una referencia a reflect-metadata.d.ts.

Necesitas implementar tus propios decoradores:

// declare property decorator
function logType(target : any, key : string) {
  var t = Reflect.getMetadata("design:type", target, key);
  console.log(`${key} type: ${t.name}`);
}

class Demo{ 
  @logType // apply property decorator
  public attr1 : string;
}

Se registrará en la consola:

attr1 type: String

Otro ejemplo:

// declare parameter decorator
function logParamTypes(target : any, key : string) {
  var types = Reflect.getMetadata("design:paramtypes", target, key);
  var s = types.map(a => a.name).join();
  console.log(`${key} param types: ${s}`);
}  

class Foo {}
interface IFoo {}

class Demo{ 
  @logParameters // apply parameter decorator
  doSomething(
    param1 : string,
    param2 : number,
    param3 : Foo,
    param4 : { test : string },
    param5 : IFoo,
    param6 : Function,
    param7 : (a : number) => void,
  ) : number { 
      return 1
  }
}

Se registrará en la consola:

doSomething param types: String, Number, Foo, Object, Object, Function, Function

Nota que las interfaces IFoo y el literal de objeto { test : string} se serializan como Object. Las reglas de serialización son:

  • number serializado como Number
  • string serializado como String
  • boolean serializado como Boolean
  • any serializado como Object
  • void se serializa como undefined
  • Array serializado como Array
  • Si un Tuple, serializado como Array
  • Si una class lo serializara como el constructor de la clase
  • Si un Enum lo serializara como Number
  • Si tiene al menos una firma de llamada, serializada como Function
  • De lo contrario, serializado como Object (Incluyendo interfaces)

Las interfaces y los literales de objetos pueden ser serializados en el futuro mediante la serialización de tipos complejos, pero esta función no está disponible en este momento.

También puedes obtener el tipo de retorno de una función usando:

Reflect.getMetadata("design:returntype", target, key);

Si necesitas más información sobre los decoradores, puedes leer: Decoradores y reflexión de metadatos en TypeScript: De novato a experto

Artículos relacionados