Los Ty­pe­S­cri­pt de­co­ra­to­rs son una he­rra­mie­n­ta práctica y sencilla para añadir funciones adi­cio­na­les a objetos sin modificar su código fuente. Puedes aplicar de­co­ra­do­res de Ty­pe­S­cri­pt a clases, métodos, pro­pie­da­des, funciones y pa­rá­me­tros de acceso, apro­ve­cha­n­do ano­ta­cio­nes y metadatos.

¿Qué son los de­co­ra­to­rs de Ty­pe­S­cri­pt y para qué se utilizan?

El concepto de Ty­pe­S­cri­pt de­co­ra­to­rs no es nuevo. Existen funciones similares en otros lenguajes de pro­gra­ma­ción, como los atributos en C#, los Python de­co­ra­to­rs o las ano­ta­cio­nes en Java. Se utilizan para ampliar la fu­n­cio­na­li­dad de un objeto sin modificar su código fuente. Ty­pe­S­cri­pt ha adoptado este enfoque, aunque la mayoría de los na­ve­ga­do­res aún no son co­m­pa­ti­bles con los de­co­ra­to­rs de Ty­pe­S­cri­pt. Aun así, vale la pena explorar sus po­si­bi­li­da­des. Desde la versión 5.0, el uso de de­co­ra­do­res se ha si­m­pli­fi­ca­do co­n­si­de­ra­ble­me­n­te.

Los de­co­ra­to­rs de Ty­pe­S­cri­pt se utilizan para añadir ano­ta­cio­nes y metadatos adi­cio­na­les a las clases de Ty­pe­S­cri­pt y a sus elementos. Además de las clases, se pueden modificar métodos, pro­pie­da­des, métodos de acceso y pa­rá­me­tros. Estos últimos pueden validarse y sus valores re­cu­pe­rar­se, lo que distingue a los de­co­ra­to­rs de Ty­pe­S­cri­pt de su equi­va­le­n­te en Ja­va­S­cri­pt.

Sintaxis y fu­n­cio­na­mie­n­to de los de­co­ra­do­res

Al añadir de­co­ra­to­rs de Ty­pe­S­cri­pt a un objeto, estás uti­li­za­n­do una función que se ejecuta sin modificar el código fuente. Los de­co­ra­do­res aumentan la fu­n­cio­na­li­dad y mantienen el código ordenado. La sintaxis básica es la siguiente:

@nombreDelDecorador
ty­pe­s­cri­pt

Esta función se define con dos o tres pa­rá­me­tros. La sintaxis para una función con tres pa­rá­me­tros 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() {
    }
}
ty­pe­s­cri­pt

Los Ty­pe­S­cri­pt de­co­ra­to­rs se componen de los si­guie­n­tes elementos:

  • target: hace re­fe­re­n­cia 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 in­fo­r­ma­ción adicional sobre el objeto al que se aplica el decorador; como value, writable, enumerable o configurable.

La sintaxis para Ty­pe­S­cri­pt de­co­ra­to­rs con dos pa­rá­me­tros es:

function funcionDecoradora(target: any) {
    console.log(`Decorando ${target.name}`);
}
@funcionDecoradora
class MiClase {
}
ty­pe­s­cri­pt

En este caso, el Ty­pe­S­cri­pt decorator se aplica a una clase.

Los di­fe­re­n­tes tipos de de­co­ra­do­res

Existen varios tipos de Ty­pe­S­cri­pt de­co­ra­to­rs, cada uno con sus pa­r­ti­cu­la­ri­da­des, que te ex­pli­ca­mos en detalle a co­n­ti­nua­ción:

  • De­co­ra­do­res de clase (class de­co­ra­to­rs)
  • De­co­ra­do­res de método (method de­co­ra­to­rs)
  • De­co­ra­do­res de pro­pie­da­des (property de­co­ra­to­rs)
  • De­co­ra­do­res de ac­ce­so­rios (accessor de­co­ra­to­rs)
  • De­co­ra­do­res de pa­rá­me­tros (parameter de­co­ra­to­rs)

Ty­pe­S­cri­pt de­co­ra­to­rs de clases

Con los Ty­pe­S­cri­pt de­co­ra­to­rs puedes pe­r­so­na­li­zar los elementos de una clase, como su co­n­s­tru­c­tor, métodos o pro­pie­da­des. El primer parámetro que recibes al “decorar” la clase con una función es el co­n­s­tru­c­tor. A co­n­ti­nua­ción, te mostramos un ejemplo de código en el que tra­ba­ja­mos con una lista de clientes. Esta clase tiene algunas pro­pie­da­des 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";
ty­pe­s­cri­pt

En el siguiente paso, uti­li­za­mos Ty­pe­S­cri­pt de­co­ra­to­rs para añadir más funciones sin alterar el código fuente. Por ejemplo, añadimos el decorador @frozen a la clase “Clientes” para ase­gu­rar­nos de que los objetos no puedan mo­di­fi­car­se po­s­te­rio­r­me­n­te. En algunas pro­pie­da­des, usamos @required para requerir que se definan ex­plí­ci­ta­me­n­te. También uti­li­za­mos @enumerable para los listados y @deprecated para señalar entradas obsoletas. Primero, definimos los de­co­ra­do­res:

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.`);
}
ty­pe­s­cri­pt

Una vez in­tro­du­ci­dos los de­co­ra­to­rs de Ty­pe­S­cri­pt, el código de­fi­ni­ti­vo 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";
ty­pe­s­cri­pt

Ty­pe­S­cri­pt de­co­ra­to­rs de métodos

También puedes utilizar de­co­ra­to­rs de Ty­pe­S­cri­pt para métodos (method de­co­ra­to­rs). Algunas ex­ce­p­cio­nes incluyen los De­cla­ra­tion Files, el Ove­r­loa­di­ng 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}`;
    }
}
ty­pe­s­cri­pt

Ty­pe­S­cri­pt de­co­ra­to­rs de pro­pie­da­des

Los Ty­pe­S­cri­pt de­co­ra­to­rs de pro­pie­da­des de una clase (property de­co­ra­to­rs) tienen dos pa­rá­me­tros: la función del co­n­s­tru­c­tor 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";
}
ty­pe­s­cri­pt

Ty­pe­S­cri­pt de­co­ra­to­rs de acceso

Los de­co­ra­do­res de acceso (accessor de­co­ra­to­rs) funcionan de manera similar a los de­co­ra­do­res de pro­pie­da­des, pero con una di­fe­re­n­cia im­po­r­ta­n­te: tienen un tercer parámetro adicional. En nuestro ejemplo, el tercer parámetro es el de­s­cri­p­tor de la propiedad para un cliente. Si aplicas un valor usando el decorador de acceso, ese valor se convierte en el nuevo de­s­cri­p­tor de la propiedad. En el siguiente código, mo­di­fi­ca­mos 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;
    }
}
ty­pe­s­cri­pt

Así se aplica el decorador:

class Clientes {
    nombre: string = "Julia";
    apellido: string = "García";
    @enumerable(true)
    get nombreCompleto() {
        return `${this.nombre} ${this.apellido}`;
    }
}
ty­pe­s­cri­pt

Ty­pe­S­cri­pt de­co­ra­to­rs de pa­rá­me­tros

Los Ty­pe­S­cri­pt de­co­ra­to­rs de pa­rá­me­tros (parameter de­co­ra­to­rs) también tienen tres pa­rá­me­tros: la función del co­n­s­tru­c­tor 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 co­m­pro­ba­cio­nes, 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}`);
}
ty­pe­s­cri­pt

Luego puedes aplicar el decorador de pa­rá­me­tros de la siguiente forma:

class Ejemplo {
    testMethod(param0: any, @print param1: any) {}
}
ty­pe­s­cri­pt
Consejo

Ideal tanto para páginas web estáticas como para apli­ca­cio­nes: con Deploy Now de IONOS, puedes be­ne­fi­ciar­te de un entorno de prueba sencillo, una co­n­fi­gu­ra­ción rápida y flujos de trabajo pe­r­fe­c­ta­me­n­te adaptados. ¡Encuentra el modelo que mejor se adapte a tus ne­ce­si­da­des!

Ir al menú principal