TypeScript decorators: clases, métodos y propiedades
Los TypeScript decorators son una herramienta práctica y sencilla para añadir funciones adicionales a objetos sin modificar su código fuente. Puedes aplicar decoradores de TypeScript a clases, métodos, propiedades, funciones y parámetros de acceso, aprovechando anotaciones y metadatos.
¿Qué son los decorators de TypeScript y para qué se utilizan?
El concepto de TypeScript decorators no es nuevo. Existen funciones similares en otros lenguajes de programación, como los atributos en C#, los Python decorators o las anotaciones en Java. Se utilizan para ampliar la funcionalidad de un objeto sin modificar su código fuente. TypeScript ha adoptado este enfoque, aunque la mayoría de los navegadores aún no son compatibles con los decorators de TypeScript. Aun así, vale la pena explorar sus posibilidades. Desde la versión 5.0, el uso de decoradores se ha simplificado considerablemente.
Los decorators de TypeScript se utilizan para añadir anotaciones y metadatos adicionales a las clases de TypeScript y a sus elementos. Además de las clases, se pueden modificar métodos, propiedades, métodos de acceso y parámetros. Estos últimos pueden validarse y sus valores recuperarse, lo que distingue a los decorators de TypeScript de su equivalente en JavaScript.
Sintaxis y funcionamiento de los decoradores
Al añadir decorators de TypeScript a un objeto, estás utilizando una función que se ejecuta sin modificar el código fuente. Los decoradores aumentan la funcionalidad y mantienen el código ordenado. La sintaxis básica es la siguiente:
@nombreDelDecorador
typescriptEsta función se define con dos o tres parámetros. La sintaxis para una función con tres parámetros es la siguiente:
function funcionDecoradora(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Decorando ${propertyKey} de la clase ${target.constructor.name}`);
}
class MiClase {
@funcionDecoradora
miMetodo() {
}
}
typescriptLos TypeScript decorators se componen de los siguientes elementos:
target
: hace referencia al objeto al que se le ha asignado el decoradorpropertyKey
: es una cadena (string) que contiene el nombre del método o propiedad al que se ha aplicado un decoradordescriptor
: almacena información adicional sobre el objeto al que se aplica el decorador; comovalue
,writable
,enumerable
oconfigurable
.
La sintaxis para TypeScript decorators con dos parámetros es:
function funcionDecoradora(target: any) {
console.log(`Decorando ${target.name}`);
}
@funcionDecoradora
class MiClase {
}
typescriptEn este caso, el TypeScript decorator se aplica a una clase.
Los diferentes tipos de decoradores
Existen varios tipos de TypeScript decorators, cada uno con sus particularidades, que te explicamos en detalle a continuación:
- Decoradores de clase (class decorators)
- Decoradores de método (method decorators)
- Decoradores de propiedades (property decorators)
- Decoradores de accesorios (accessor decorators)
- Decoradores de parámetros (parameter decorators)
TypeScript decorators de clases
Con los TypeScript decorators puedes personalizar los elementos de una clase, como su constructor, métodos o propiedades. El primer parámetro que recibes al “decorar” la clase con una función es el constructor. A continuación, te mostramos un ejemplo de código en el que trabajamos con una lista de clientes. Esta clase tiene algunas propiedades privadas y otras públicas:
class Clientes {
private static tipoUsuario: string = "Genérico";
private _email: string;
public nombreCliente: string;
public calle: string = "";
public ciudad: string = "";
public pais: string = "";
constructor(nombreCliente: string, email: string) {
this.nombreCliente = nombreCliente;
this._email = email;
}
Static get tipoUsuario() {
return Clientes.tipoUsuario;
}
get email() {
return this._email;
}
set email(nuevoEmail: string) {
this._email = nuevoEmail;
}
direccion(): string {
return `${this.calle}\n${this.ciudad}\n${this.pais}`;
}
}
const p = new Clientes("clienteEjemplo", "nombre@ejemplo.com");
p.calle = "Calle Mayor, 2";
p.ciudad = "Madrid";
typescriptEn el siguiente paso, utilizamos TypeScript decorators para añadir más funciones sin alterar el código fuente. Por ejemplo, añadimos el decorador @frozen
a la clase “Clientes” para asegurarnos de que los objetos no puedan modificarse posteriormente. En algunas propiedades, usamos @required
para requerir que se definan explícitamente. También utilizamos @enumerable
para los listados y @deprecated
para señalar entradas obsoletas. Primero, definimos los decoradores:
function frozen(constructor: Function) {
Object.freeze(constructor);
Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
// Lógica para el decorador Required
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
function deprecated(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.warn(`El método ${propertyKey} está obsoleto.`);
}
typescriptUna vez introducidos los decorators de TypeScript, el código definitivo tiene el siguiente aspecto:
@frozen
class Clientes {
private static tipoUsuario: string = "Genérico";
@required
private _email: string;
@required
public nombreCliente: string;
public calle: string = "";
public ciudad: string = "";
public pais: string = "";
constructor(nombreCliente: string, email: string) {
this.nombreCliente = nombreCliente;
this._email = email;
}
@enumerable(false)
get tipoUsuario() {
return Clientes.tipoUsuario;
}
get email() {
return this._email;
}
set email(nuevoEmail: string) {
this._email = nuevoEmail;
}
@deprecated
direccion(): string {
return `${this.calle}\n${this.ciudad}\n${this.pais}`;
}
}
const p = new Clientes("clienteEjemplo", "nombre@ejemplo.com");
p.calle = "Calle Mayor, 2";
p.ciudad = "Madrid";
typescriptTypeScript decorators de métodos
También puedes utilizar decorators de TypeScript para métodos (method decorators). Algunas excepciones incluyen los Declaration Files, el Overloading o la clase “declare”. En el siguiente ejemplo, usamos @enumerable
como decorador para el método getName
de la clase “Persona”:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
propertyDescriptor.enumerable = value;
}
}
class Persona {
nombre: string = "Julia"
apellido: string = "García"
@enumerable(true)
getName () {
return `${this.nombre} ${this.apellido}`;
}
}
typescriptTypeScript decorators de propiedades
Los TypeScript decorators de propiedades de una clase (property decorators) tienen dos parámetros: la función del constructor de la clase y el nombre de la propiedad. En el siguiente ejemplo, usamos el decorador para mostrar el nombre de una propiedad (en este caso, el nombre del cliente):
const printPropertyName = (target: any, propertyName: string) => {
console.log(propertyName);
};
class Clientes {
@printPropertyName
nombre: string = "Julia";
}
typescriptTypeScript decorators de acceso
Los decoradores de acceso (accessor decorators) funcionan de manera similar a los decoradores de propiedades, pero con una diferencia importante: tienen un tercer parámetro adicional. En nuestro ejemplo, el tercer parámetro es el descriptor de la propiedad para un cliente. Si aplicas un valor usando el decorador de acceso, ese valor se convierte en el nuevo descriptor de la propiedad. En el siguiente código, modificamos el valor booleano (“true” o “false”) de enumerable
. Aquí tienes nuestro punto de partida:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
descriptor.enumerable = value;
}
}
typescriptAsí se aplica el decorador:
class Clientes {
nombre: string = "Julia";
apellido: string = "García";
@enumerable(true)
get nombreCompleto() {
return `${this.nombre} ${this.apellido}`;
}
}
typescriptTypeScript decorators de parámetros
Los TypeScript decorators de parámetros (parameter decorators) también tienen tres parámetros: la función del constructor de la clase, el nombre del método y un índice que designa el parámetro. Sin embargo, el decorador solo se puede utilizar para realizar comprobaciones, no para modificar el parámetro en sí. Si quieres consultar el índice, puedes hacerlo con el siguiente código:
function print(target: Object, propertyKey: string, parameterIndex: number) {
console.log(`Decorando parámetro ${parameterIndex} de ${propertyKey}`);
}
typescriptLuego puedes aplicar el decorador de parámetros de la siguiente forma:
class Ejemplo {
testMethod(param0: any, @print param1: any) {}
}
typescriptIdeal tanto para páginas web estáticas como para aplicaciones: con Deploy Now de IONOS, puedes beneficiarte de un entorno de prueba sencillo, una configuración rápida y flujos de trabajo perfectamente adaptados. ¡Encuentra el modelo que mejor se adapte a tus necesidades!