TypeScript es un lenguaje de programación fuertemente tipado que se basa en JavaScript, ofreciéndole mejores herramientas a escala. TypeScript se desarrolló para ayudar a resolver algunos de los problemas que surgen al escribir código utilizando JavaScript. TypeScript supera los escollos de JavaScript mediante el uso de tipos.

Cada valor en un código fuente TypeScript tiene un tipo. TypeScript comprueba que cada valor cumple las reglas asociadas a su tipo. TypeScript comprueba si hay errores en su código fuente sin que usted tenga que ejecutar o poner en marcha su programa.

Esto se denomina comprobación estática de tipos, que consiste en buscar errores en el desarrollo basándose en el tipo de los valores utilizados en un programa.

Aparte de ayudarle a escribir un código más claro y legible y de proporcionarle la comprobación estática de tipos, TypeScript ofrece características adicionales que ayudan a la legibilidad, reutilización y mantenimiento del código. Una de estas características son los decoradores TypeScript.

Decoradores TypeScript

TypeScript-Decorators

Los decoradores en TypeScript son una característica que le permite alterar o mejorar el comportamiento de su código en tiempo de ejecución o añadir metadatos a su código. Los decoradores permiten la metaprogramación en TypeScript. La metaprogramación es una técnica de programación en la que los programas pueden tratar a otros programas como sus datos y modificar así su comportamiento.

Esencialmente, los decoradores son funciones que serán llamadas para ejecutar alguna lógica en tiempo de ejecución cuando los elementos decorados sean accedidos o modificados.

De esta forma, se puede añadir funcionalidad adicional a los elementos decorados. Los decoradores TypeScript pueden adjuntarse a declaraciones de clases, métodos, propiedades, accesores (getters y setters) y parámetros de métodos.

En TypeScript, los decoradores llevan como prefijo el símbolo @, y adoptan la forma de @expresión con expresión que evalúa a una función que será llamada en tiempo de ejecución. La sintaxis general para utilizar decoradores en TypeScript es la que se muestra a continuación:

@nombreDecorador
itemToDecorate

A continuación se muestra un ejemplo de un decorador de clase simple:

function logClass(objetivo: Function) {
  console.log("Se ha llamado al decorador de clase log")
  console.log("Clase:", objetivo);
}

@logClass // @logClass es un decorador
clase MiClase {
  constructor() {
    console.log("Se ha creado una instancia de MiClase");
  }
}

const miInstancia = nueva MiClase();

A continuación se muestra el resultado de ejecutar el código anterior:

Salida:

El Decorador de Clase Log ha sido llamado
Clase [clase MiClase]
Se ha creado una instancia de MyClass
ts-decorator

La función logClass( ) recibe un único argumento llamado target de tipo Function. El argumento target es de tipo Function porque recibirá el constructor de la clase que estamos decorando.

Para utilizar logClass( ) como decorador para decorar la clase llamada MyClass ponemos @logclass justo antes de la declaración de MyClass. El decorador debe tener el mismo nombre que la función que desea utilizar para decorar un elemento.

Cuando se crea una instancia de MyClass, el comportamiento del decorador se ejecuta además del constructor de la clase, como muestra la salida.

Los decoradores están disponibles actualmente en Typescript como una función experimental. Por lo tanto, para que pueda utilizar decoradores en TypeScript, necesita habilitar la opción experimentalDecorators en el compilador en el archivo tsconfig.json.

Para ello, genere un archivo tsconfig.json en la carpeta de su proyecto TypeScript ejecutando el siguiente comando en el terminal abierto en el directorio de su proyecto:

tsc --init

Una vez que tenga un archivo tsconfig.json, ábralo y descomente experimentalDecorators como se muestra a continuación:

tsconfig-file

Además, establezca su versión objetivo de JavaScript como mínimo en ES2015.

Importancia de los decoradores TypeScript

Un buen código puede determinarse fácilmente por lo legible, reutilizable y mantenible que sea el código. El código legible es aquel que es fácil de entender e interpretar y que comunica claramente la intención del desarrollador a quien esté leyendo el código.

Por otro lado, el código reutilizable es aquel que permite que componentes específicos, como funciones y clases, puedan reutilizarse, adaptarse y usarse en otras partes de una aplicación o en una aplicación completamente nueva sin modificaciones significativas.

El código mantenible es aquel que puede modificarse, actualizarse y arreglarse fácilmente a lo largo de su vida útil.

Best Source Code Hosting Solutions for Small Businesses to Enterprise

Los decoradores de TypeScript le permiten lograr la legibilidad, reutilización y mantenibilidad del código. En primer lugar, los decoradores de TypeScript le permiten mejorar el comportamiento de su código utilizando una sintaxis declarativa más fácil de leer. Puede encapsular la lógica en decoradores e invocarlos decorando diferentes elementos de su código donde necesite la lógica.

Esto hace que su código sea fácil de leer y de entender lo que está pasando. Los decoradores comunican claramente la intención del desarrollador.

Los decoradores no son elementos de un solo uso; son reutilizables por naturaleza. Puede crear un decorador una vez y utilizarlo varias veces en múltiples áreas.

Por lo tanto, puede definir decoradores, importarlos y utilizarlos en cualquier lugar de su base de código donde desee modificar el comportamiento de su código. Esto es beneficioso, ya que le permite evitar duplicar la lógica en su base de código, mejorando así la reutilización de su código.

Los decoradores también le proporcionan una gran flexibilidad y modularidad en su código, permitiéndole separar diferentes funcionalidades en componentes independientes. Esto, unido al hecho de que permiten escribir código legible y reutilizable, significa que los decoradores de TypeScript le permitirán tener un código fácil de mantener.

Tipos de decoradores de TypeScript

Como se ha señalado anteriormente, los decoradores de TypeScript pueden adjuntarse a clases, propiedades de clases, métodos de clases, accesores de clases y parámetros de métodos de clases. A partir de los elementos que podemos decorar, obtenemos los diferentes tipos de decoradores TypeScript. Estos decoradores incluyen:

#1. Decorador de clase

Un decorador de clase es un decorador utilizado para observar, modificar o reemplazar la definición de una clase. Se declara justo antes de la clase que está decorando. Un decorador de clase se aplica al constructor de la clase que está decorando. En tiempo de ejecución, un decorador de clase será llamado con el constructor de la clase que está decorando como único argumento.

A continuación se muestra un decorador de clase que se utiliza para evitar que se extienda una clase:

function congelado(objetivo: Función) {
  Object.freeze(objetivo);
  Object.freeze(target.prototype)
}

@congelado
clase Vehículo {
  ruedas: número = 4;
  constructor() {
    console.log("Se ha creado un vehículo")
  }
}

class Coche extends Vehículo {
  constructor() {
    super();
    console.log("Se ha creado un coche");
  }
}

console.log(Object.isFrozen(Vehículo));

Para evitar que una clase se extienda, utilizamos la función Object.freeze() y le pasamos la clase que queremos congelar. Para añadir esta funcionalidad a una clase se utiliza un decorador. Podemos comprobar si la clase Vehículo está congelada en tiempo de ejecución pasando la clase a isFrozen(), la salida del código se muestra a continuación:

true
frozen-class

#2. Decorador de propiedades

Un decorador de propiedades se utiliza para decorar una propiedad de la clase, y se declara justo antes de la decoración de la propiedad. Los decoradores de propiedades se pueden utilizar para cambiar u observar la definición de una propiedad.

En tiempo de ejecución, el decorador será llamado, y toma dos argumentos. El primero es la función constructora de la clase si el miembro es estático o el prototipo de la clase en caso de que sea un miembro de instancia. El segundo argumento es el nombre del miembro, es decir, la propiedad que está decorando.

En TypeScript, los miembros estáticos llevan la palabra clave static delante. Se puede acceder a los miembros estáticos sin instanciar una clase. Los miembros de instancia no tienen la palabra clave static delante y sólo se puede acceder a ellos después de haber creado una instancia de una clase.

A continuación se muestra un ejemplo de decorador de propiedades:

function wheelsDecorator(target: any, propertyName: string) {
  console.log(propertyName.toUpperCase())
}

clase Vehículo {
  @ruedasDecorador
  ruedas: número = 4;
  constructor() {
    console.log("Se ha creado un vehículo")
  }
}

La salida de la ejecución del código se muestra a continuación:

RUEDAS
property-decorator

#3. Decorador de método

Un decorador de método, declarado justo antes de la declaración de un método es un decorador utilizado para observar, modificar o reemplazar la definición de un método. Toma tres argumentos, la función constructora de la clase en caso de que el miembro sea estático o la propiedad de la clase si se trata de un miembro de instancia.

El segundo argumento es el nombre del miembro y, por último, un descriptor de propiedad para el miembro. Un descriptor de propiedad es un objeto asociado a las propiedades de un objeto, y proporciona información sobre los atributos y el comportamiento de una propiedad.

Los decoradores de métodos resultan útiles cuando queremos realizar alguna acción antes o después de llamar a un método. También podemos utilizarlos para registrar información sobre el método que se está llamando. Esto puede ser útil en caso de que quiera informar a un usuario de que un método está obsoleto; es decir, que todavía está disponible para su uso, pero no es recomendable que lo utilice ya que puede ser eliminado más adelante.

A continuación se muestra un ejemplo de decorador de métodos:

const logDeprecated =(target: any, methodName: string, descriptor: PropertyDescriptor) => {
  console.log(`${nombredemétodo} ha sido obsoleto`)
  console.log(descriptor);
}

class Vehículo {
  ruedas: número = 4;
  constructor() {
    console.log("Se ha creado un vehículo")
  }
  @logDeprecated
  repostar(): void {
    console.log("Su vehículo está repostando");
  }
}

Salida:

reFuel ha sido obsoleto
{
  valor: [Función: reFuel],
  escribible: true
  enumerable: false
  configurable: true
}
method-decorator-ts

#4. Decoradores de accesores

En TypeScript, hay dos tipos de métodos accesores, get y set. Los métodos accessor se utilizan para controlar el acceso a las propiedades de la clase. Los decoradores de accesores se utilizan para decorar estos dos métodos de accesores, y se declaran justo antes de una declaración de accesores. Dado que los accesores siguen siendo métodos, los decoradores de accesores funcionan igual que los decoradores de métodos.

A continuación se muestra un ejemplo de un decorador de accesores:

const logRuedas =(target: any, accessorName: string, descriptor: PropertyDescriptor) => {
  console.log(`${accessorName} utilizado para obtener el número de ruedas`)
  console.log(descriptor);
}

clase Vehículo {
  privado ruedas: número = 4;
  constructor() {
    console.log("Se ha creado un vehículo")
  }
  @logRuedas
  get numeroRuedas(): numero {
    return this.wheels;
  }
}

Salida:

numWheels se utiliza para obtener el número de ruedas
{
  obtener: [Función: get numRuedas],
  set: indefinido,
  enumerable: false
  configurable: true
}
accessor-decorators

Con los decoradores de accesores, es importante tener en cuenta que los decoradores no pueden aplicarse a múltiples accesores get/set del mismo nombre. Por ejemplo, en nuestro ejemplo de código anterior, si crea un setter llamado set numRuedas, no puede utilizar el decorador logRuedas en él.

#5. Decoradores de parámetros

Un decorador de parámetro se utiliza para observar que se ha declarado un parámetro en un método, y se declara antes de una declaración de parámetro. Los decoradores de parámetros toman tres argumentos, el primero, la función constructora de la clase para un miembro estático o el prototipo de la clase para un miembro de instancia.

El segundo argumento es el nombre del miembro, es decir, el nombre del parámetro. El tercer argumento es el índice ordinal del parámetro en la lista de parámetros de la función. Es decir, en la lista de parámetros, ¿en qué posición se encuentra el parámetro, estando el primer parámetro en el índice 0?

A continuación se muestra un ejemplo de decorador de parámetros:

const passengerLog = (target: Objeto, propertyKey: cadena, parameterIndex: número) => {
  console.log(`Decorador en el índice de parámetro ${propertyKey} ${parameterIndex}`);
}

clase Vehículo {
  private ruedas: número = 4;
  constructor() {
    console.log("Se ha creado un vehículo")
  }
  pickPassenger( ubicación: cadena, numPassengers: cadena, @passengerLog conductor: cadena) {
    console.log(`${numPassengers} recogido en ${ubicación} por ${conductor}`)
  }
  dropPassenger(conductor: cadena, @passengerLog ubicación: cadena, numPassengers: cadena) {
    console.log(`${numPasajeros} recogidos en ${ubicación} por ${conductor}`)
  }
}

Salida:

Decorador en el índice 2 del paremeter de pickPassenger
Decorador en el índice 1 del paremeter de dropPassenger
parameter-decorator-ts

Conclusión

Los decoradores de TypeScript contribuyen en gran medida a mejorar la legibilidad de su código y a ayudarle a escribir código modular y reutilizable, ya que puede declarar los decoradores una vez y utilizarlos muchas veces. Además, los decoradores contribuyen a la mantenibilidad general de su código.

Por mucho que todavía sean una característica experimental, los decoradores son muy útiles, y definitivamente debería considerar familiarizarse con ellos.

También puede leer cómo convertir una cadena en un número en TypeScript.