
TypeScript: Decoradores y metaprogramación
- Dacadev
- Programación
- 22 de junio de 2026
Tabla de Contenido
Note
Noveno artículo de la serie sobre TypeScript. Estudiaremos los decoradores: funciones que se ejecutan en la definición de clases, métodos y propiedades para extender su comportamiento sin modificar su código original.
Un decorador en TypeScript es una función que se ejecuta en tiempo de transpilación y permite expandir la funcionalidad de un objeto —clase, método o propiedad— de forma declarativa. Frameworks como Angular o NestJS apoyan gran parte de su ergonomía en este mecanismo. Analicemos cada variante con ejemplos prácticos. Puedes consultar la referencia completa en la documentación oficial de decoradores.
Info
Los decoradores se colocan con la sintaxis @nombre justo antes del elemento a decorar. Por convención se declaran con function —en lugar de arrow functions— para distinguirlos visualmente de las funciones ordinarias.
Decoradores de clase
Un decorador de clase recibe el constructor y se ejecuta una sola vez, en el momento en que se define la clase —no al crear cada instancia:
function printToConsole(constructor: Function) {
console.log(constructor)
}
@printToConsole
export class Pokemon {
public publicApi: string = 'https://pokeapi.co'
constructor(public name: string) {}
}
Al crear varias instancias, el decorador no vuelve a ejecutarse: su efecto ocurre en la definición, no en la instanciación.
Decoradores de fábrica
Un decorador de fábrica es una función que retorna el decorador real. Esto permite parametrizar el comportamiento, aceptando argumentos que controlan cómo se aplica:
function printToConsole(constructor: Function) {
console.log(constructor)
}
const printToConsoleConditional = (print: boolean = true): Function => {
return print ? printToConsole : () => {}
}
@printToConsoleConditional(false)
export class Pokemon {
public publicApi: string = 'https://pokeapi.co'
constructor(public name: string) {}
}
Un patrón habitual es sellar el prototipo para impedir que se alteren sus propiedades en tiempo de ejecución:
const blockPrototype = function (constructor: Function) {
Object.seal(constructor)
Object.seal(constructor.prototype)
}
@blockPrototype
@printToConsoleConditional(false)
export class Pokemon {
// ...
}
Tip
Cuando aplicas múltiples decoradores, se ejecutan de forma secuencial de abajo hacia arriba. En el ejemplo anterior, primero corre printToConsoleConditional y luego blockPrototype.
Decoradores de método
Un decorador de método recibe tres argumentos —el objeto al que pertenece, el nombre del método y su PropertyDescriptor— y puede inspeccionar o reemplazar por completo el comportamiento del método. Aquí lo usamos para validar argumentos:
function CheckValidPokemonId() {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value
descriptor.value = (id: number) => {
if (id < 1 || id > 100) {
return console.error('El id del pokemon debe estar entre 1 y 100')
}
return originalMethod(id)
}
}
}
export class Pokemon {
public publicApi: string = 'https://pokeapi.co'
constructor(public name: string) {}
@CheckValidPokemonId()
savePokemonToDB(id: number) {
console.log(`Pokemon guardado en la base de datos ${id}`)
}
}
Al envolver originalMethod, el decorador intercepta la llamada, valida el id y solo delega al método original cuando el valor es válido. Este es el fundamento de las validaciones declarativas de muchos frameworks.
Decoradores de propiedad
Un decorador de propiedad recibe el objeto y el nombre de la propiedad, y puede alterar cómo se lee y escribe. Es útil para controlar el acceso a datos —recordando que JavaScript no tiene propiedades verdaderamente privadas en runtime:
function readOnly(isWriteable: boolean = true): Function {
return function (target: any, propertyKey: string) {
const descriptor: PropertyDescriptor = {
get() {
return 'Daca code'
},
set(this, val) {
Object.defineProperty(this, propertyKey, {
value: val,
writable: !isWriteable,
enumerable: false
})
}
}
return descriptor
}
}
export class Pokemon {
@readOnly(false)
private publicApi: string = 'https://pokeapi.co'
constructor(public name: string) {}
}
El decorador define un get/set personalizado que gobierna por completo el acceso a publicApi.
Conclusión
Los decoradores aportan metaprogramación declarativa a TypeScript: el decorador de clase actúa sobre el constructor una única vez, el de fábrica parametriza el comportamiento, el de método intercepta y reemplaza llamadas, y el de propiedad controla la lectura y escritura. Componerlos en cadena —respetando su orden de ejecución— es lo que habilita las APIs elegantes de frameworks modernos.
En el próximo artículo organizaremos el código con namespaces y módulos: export, import, alias y exportaciones por defecto.


