Los decoradores en TypeScript son una característica poderosa que permite modificar el comportamiento de clases, métodos, propiedades y parámetros. Los decoradores son una forma de metaprogramación que se puede utilizar para añadir anotaciones y una lógica predefinida a las estructuras de código.
¿Qué son los Decoradores?
Un decorador es una función especial que se puede aplicar a una clase, método, accesor, propiedad o parámetro. Los decoradores se definen con el símbolo @
seguido del nombre del decorador y se colocan justo antes de la declaración que desean modificar.
Tipos de Decoradores
- Decoradores de Clase: Se aplican a una clase.
- Decoradores de Método: Se aplican a un método de una clase.
- Decoradores de Accesor: Se aplican a un accesor (getter o setter) de una clase.
- Decoradores de Propiedad: Se aplican a una propiedad de una clase.
- Decoradores de Parámetro: Se aplican a un parámetro de un método de una clase.
Ejemplo Básico de Decorador de Clase
Vamos a empezar con un ejemplo simple de un decorador de clase. Este decorador añadirá una propiedad estática a la clase.
function addStaticProperty(constructor: Function) { constructor.prototype.staticProperty = "I am a static property"; } @addStaticProperty class MyClass { constructor() { console.log("MyClass instance created"); } } const myInstance = new MyClass(); console.log((myInstance as any).staticProperty); // Output: I am a static property
Explicación
- Definición del Decorador:
addStaticProperty
es una función que toma el constructor de la clase como argumento y añade una propiedad estática a su prototipo. - Aplicación del Decorador: El decorador
@addStaticProperty
se aplica a la claseMyClass
. - Uso de la Clase: Al crear una instancia de
MyClass
, podemos acceder a la propiedad estática añadida por el decorador.
Decoradores de Método
Los decoradores de método se utilizan para modificar el comportamiento de los métodos de una clase. Vamos a crear un decorador que loguea el tiempo de ejecución de un método.
function logExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const start = performance.now(); const result = originalMethod.apply(this, args); const end = performance.now(); console.log(`Execution time of ${propertyKey}: ${end - start}ms`); return result; }; return descriptor; } class Example { @logExecutionTime compute() { // Simulate a time-consuming task for (let i = 0; i < 1e6; i++) {} } } const example = new Example(); example.compute(); // Output: Execution time of compute: Xms
Explicación
- Definición del Decorador:
logExecutionTime
es una función que toma el objeto objetivo (target
), la clave de la propiedad (propertyKey
) y el descriptor del método (descriptor
). - Modificación del Método: El decorador reemplaza el método original con una nueva función que mide el tiempo de ejecución y luego llama al método original.
- Aplicación del Decorador: El decorador
@logExecutionTime
se aplica al métodocompute
de la claseExample
.
Decoradores de Propiedad
Los decoradores de propiedad se utilizan para modificar las propiedades de una clase. Vamos a crear un decorador que convierte una propiedad en solo lectura.
function readonly(target: any, propertyKey: string) { Object.defineProperty(target, propertyKey, { writable: false }); } class Person { @readonly name: string; constructor(name: string) { this.name = name; } } const person = new Person("John"); person.name = "Doe"; // Error: Cannot assign to read only property 'name'
Explicación
- Definición del Decorador:
readonly
es una función que toma el objeto objetivo (target
) y la clave de la propiedad (propertyKey
). - Modificación de la Propiedad: El decorador utiliza
Object.defineProperty
para hacer que la propiedad sea de solo lectura. - Aplicación del Decorador: El decorador
@readonly
se aplica a la propiedadname
de la clasePerson
.
Ejercicio Práctico
Ejercicio
Crea un decorador de método llamado logArguments
que registre los argumentos pasados a un método cada vez que se llame.
function logArguments(target: any, propertyKey: string, descriptor: PropertyDescriptor) { // Tu código aquí } class Calculator { @logArguments add(a: number, b: number): number { return a + b; } } const calculator = new Calculator(); calculator.add(2, 3); // Output: Arguments for add: [2, 3]
Solución
function logArguments(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Arguments for ${propertyKey}: ${JSON.stringify(args)}`); return originalMethod.apply(this, args); }; return descriptor; } class Calculator { @logArguments add(a: number, b: number): number { return a + b; } } const calculator = new Calculator(); calculator.add(2, 3); // Output: Arguments for add: [2, 3]
Explicación
- Definición del Decorador:
logArguments
es una función que toma el objeto objetivo (target
), la clave de la propiedad (propertyKey
) y el descriptor del método (descriptor
). - Modificación del Método: El decorador reemplaza el método original con una nueva función que registra los argumentos y luego llama al método original.
- Aplicación del Decorador: El decorador
@logArguments
se aplica al métodoadd
de la claseCalculator
.
Conclusión
Los decoradores en TypeScript son una herramienta poderosa para modificar y extender el comportamiento de clases, métodos, propiedades y parámetros. En esta sección, hemos cubierto los conceptos básicos de los decoradores y hemos visto ejemplos prácticos de cómo se pueden utilizar. Con esta base, estarás preparado para explorar y aplicar decoradores en tus propios proyectos.
En el siguiente módulo, profundizaremos en la programación asíncrona con TypeScript, comenzando con las promesas.
Curso de TypeScript
Módulo 1: Introducción a TypeScript
- ¿Qué es TypeScript?
- Configuración del Entorno de TypeScript
- Tipos Básicos
- Anotaciones de Tipo
- Compilando TypeScript
Módulo 2: Trabajando con Tipos
Módulo 3: Tipos Avanzados
Módulo 4: Funciones y Módulos
- Tipos de Función
- Parámetros Opcionales y Predeterminados
- Parámetros Rest
- Módulos y Espacios de Nombres
- Decoradores
Módulo 5: Programación Asíncrona
Módulo 6: Herramientas y Mejores Prácticas
- Linting y Formateo
- Pruebas de Código TypeScript
- TypeScript con Webpack
- TypeScript con React
- Mejores Prácticas