Bienvenidos sean a este post, hoy veremos una particularidad de los decoradores.
Al ya experimental soporte a los decoradores, typescript agrega otro como son los metadatos para cargar datos extras en estos y puedan ser usados. Estos tienen la particularidad de proveer un poco mas de informacion para indicar como se utiliza el decorador, para habilitarlo deben ir al archivo tsconfig.json y descomentar la siguiente linea:
"emitDecoratorMetadata": true,
Otro detalle mas es que el estado debe ser true, en caso de no estarlo en el archivo, y con esto ya lo tenemos habilitado. Tomemos el siguiente codigo:
function decorarParam(dest: any, nombre: string, indice: number) {}
class clase {
mostrar(@decorarParam id: string, usuario: string, nombre: string) {}
}
En este caso tenemos un codigo simple con un decorador de parametros y luego una clase con un metodo con unos parametros y al inicial de este le aplicamos el decorador. Si lo compilamos y ejecutammos no hara nada pero si miramos el archivo generado tendremos el siguiente codigo:
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
function decorarParam(dest, nombre, indice) { }
class clase {
mostrar(id, usuario, nombre) { }
}
__decorate([
__param(0, decorarParam),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String, String]),
__metadata("design:returntype", void 0)
], clase.prototype, "mostrar", null);
Nos agrego bastante mas informacion de la que teniamos pero enfoquemonos en esto:
function decorarParam(dest, nombre, indice) { }
class clase {
mostrar(id, usuario, nombre) { }
}
__decorate([
__param(0, decorarParam),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String, String]),
__metadata("design:returntype", void 0)
], clase.prototype, "mostrar", null);
Lo primero que notaremos que al inicio nos definio algunas funciones que luego son llamadas, en este caso __decorate y en ella tenemos varios llamados, el primero para el parametro con el decorador y su ubicacion y luego tenemos varios llamados a __metadata donde almacenaremos los distintos valores del diseño. En el primer caso almacena que es una funcion, lo siguientte son los tipos de argumentos y por ultimo el tipo de dato que devuelve. En cambio si la linea que habilitamos le establecemos el valor de false, el codigo compilado sera el siguiente:
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
function decorarParam(dest, nombre, indice) { }
class clase {
mostrar(id, usuario, nombre) { }
}
__decorate([
__param(0, decorarParam)
], clase.prototype, "mostrar", null);
Es un codigo muy similar al que obtuvimos anteriormente pero la diferencia principal la tendremos en el __decorate donde solo tenemos un solo campo que es __param. Volvamos a poner en estado true a la linea anterior y vamos a trabajar con un ejemplo, para ello lo primero que haremos sera ejecutar el siguiente comando:
$ npm install reflect-metadata
Este nos instalara este paquete para poder utilizar los metadatos generados. Con esto configurado nuestro siguiente paso sera crear un nuevo archivo con el siguiente codigo:
import 'reflect-metadata';
function decorarParam(dest: any,
nombre: string,
indice: number) {
let tipoDiseno = Reflect.getMetadata("design:type", dest, nombre);
console.log('design type: ' + tipoDiseno.name);
let tipoParamDiseno = Reflect.getMetadata(
"design:paramtypes", dest, nombre);
for(let tipoParam of tipoParamDiseno) {
console.log('param type: ' + tipoParam);
}
let tipoRetornoDiseno = Reflect.getMetadata(
"design:returntype", dest, nombre);
console.log('return type: ' + tipoRetornoDiseno);
}
class clase {
mostrar(
@decorarParam
id: number,
usuario: string,
nombre: string
): number
{
return 1000;
}
}
Primero importaremos nuestro nuevo paquete, lo siguiente es la funcion decoradora. En este caso tenemos uno de parametros nuevamente con sus respectivos argumentos. Lo nuevo es la definicion de tres variables donde recibiremos los valores de metadata. El primero sera para el parametro design:type, en este caso el tipo donde esta nuestro parametro para luego mostrarlo en la consola. El siguiente es para design:types, los parametros del metodo en esta ocasion, y al igual que el anterior tambien lo mostraremos en pantalla pero en esta ocasion mediante un ciclo for porque tendremos mas de un valor. El ultimo sera para design:returntype, el tipo que devolvemos del metodo, y tambien mostraremos el resultado obtenido. Lo siguiente es la definicion de la clase y en esta tendremos el metodo y dentro de este aplicaremos el decorador para el primer parametro y a este lo haremos devolver un valor numerico. Compilemos y veamos su salida:
$ node decorar.js
design type: Function
param type: function Number() { [native code] }
param type: function String() { [native code] }
param type: function String() { [native code] }
return type: function Number() { [native code] }
$
Estos son los datos que se almacenan para el metadata. Como pueden observar son un detalle de cada elemento que rodean a nuestro decorador, como es el tipo donde se usa (function), los tipos de datos de cada uno de sus parametros/argumentos, asi como tambien el tipo de dato que devuelve la funcion o en este caso el metodo. Es solo una curiosidad que nos puede ser muy util para cuando debemos depurar el codigo u obtener datos relacionados a nuestro codigo.
En resumen, hoy hemos visto a los metadatos de los decoradores, que son, para que sirven, como se habilitan, asi como tambien modifican nuestro codigo para generar estos datos y un ejemplo para poder obtener los mismos.. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
