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
typescript

Esta 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() {
    }
}
typescript

Los TypeScript decorators se componen de los siguientes elementos:

  • target: hace referencia al objeto al que se le ha asignado el decorador
  • propertyKey: es una cadena (string) que contiene el nombre del método o propiedad al que se ha aplicado un decorador
  • descriptor: almacena información adicional sobre el objeto al que se aplica el decorador; como value, writable, enumerable o configurable.

La sintaxis para TypeScript decorators con dos parámetros es:

function funcionDecoradora(target: any) {
    console.log(`Decorando ${target.name}`);
}
@funcionDecoradora
class MiClase {
}
typescript

En 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";
typescript

En 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.`);
}
typescript

Una 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";
typescript

TypeScript 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}`;
    }
}
typescript

TypeScript 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";
}
typescript

TypeScript 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;
    }
}
typescript

Así se aplica el decorador:

class Clientes {
    nombre: string = "Julia";
    apellido: string = "García";
    @enumerable(true)
    get nombreCompleto() {
        return `${this.nombre} ${this.apellido}`;
    }
}
typescript

TypeScript 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}`);
}
typescript

Luego puedes aplicar el decorador de parámetros de la siguiente forma:

class Ejemplo {
    testMethod(param0: any, @print param1: any) {}
}
typescript
Consejo

Ideal 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!

¿Le ha resultado útil este artículo?
Ir al menú principal