JavaScript Avançado

Decorators em TypeScript: Metadata, Reflection e uso com NestJS na Prática

6 min de leitura

Decorators em TypeScript: Metadata, Reflection e uso com NestJS na Prática

O que são Decorators em TypeScript? Decorators são uma funcionalidade experimental do TypeScript que permite adicionar metadados e modificar comportamentos de classes, métodos, propriedades e parâmetros em tempo de execução. Eles funcionam como funções que envolvem declarações, permitindo reutilizar lógica de forma elegante e declarativa. Essa é uma feature poderosa, especialmente quando combinada com reflection, tornando possível criar frameworks sofisticados como o NestJS. Para usar decorators, você deve habilitar a flag no . Existem cinco tipos principais: class decorators, method decorators, accessor decorators, property decorators e parameter decorators. Cada um opera em um nível diferente da hierarquia do código, permitindo controle fino sobre metadados e modificações. Metadata e Reflection com reflect-metadata Reflection é a capacidade de um programa inspecionar sua própria estrutura em tempo de execução. A biblioteca estende o Object global com métodos que permitem armazenar e recuperar metadados arbitrários. Isso é essencial para frameworks que precisam entender tipos e comportamentos dinamicamente. Instale com . O decorator com captura

<h2>O que são Decorators em TypeScript?</h2>

<p>Decorators são uma funcionalidade experimental do TypeScript que permite adicionar metadados e modificar comportamentos de classes, métodos, propriedades e parâmetros em tempo de execução. Eles funcionam como funções que envolvem declarações, permitindo reutilizar lógica de forma elegante e declarativa. Essa é uma feature poderosa, especialmente quando combinada com reflection, tornando possível criar frameworks sofisticados como o NestJS.</p>

<p>Para usar decorators, você deve habilitar a flag <code>experimentalDecorators</code> no <code>tsconfig.json</code>. Existem cinco tipos principais: class decorators, method decorators, accessor decorators, property decorators e parameter decorators. Cada um opera em um nível diferente da hierarquia do código, permitindo controle fino sobre metadados e modificações.</p>

<pre><code class="language-json">{

&quot;compilerOptions&quot;: {

&quot;experimentalDecorators&quot;: true,

&quot;emitDecoratorMetadata&quot;: true,

&quot;target&quot;: &quot;ES2020&quot;,

&quot;lib&quot;: [&quot;ES2020&quot;]

}

}</code></pre>

<h2>Metadata e Reflection com reflect-metadata</h2>

<p>Reflection é a capacidade de um programa inspecionar sua própria estrutura em tempo de execução. A biblioteca <code>reflect-metadata</code> estende o Object global com métodos que permitem armazenar e recuperar metadados arbitrários. Isso é essencial para frameworks que precisam entender tipos e comportamentos dinamicamente. Instale com <code>npm install reflect-metadata</code>.</p>

<p>O decorator com <code>emitDecoratorMetadata</code> captura informações de tipo automaticamente. Você pode então usar <code>Reflect.getMetadata()</code> para recuperar essas informações. No exemplo abaixo, criamos um decorator que registra tipos de parâmetros:</p>

<pre><code class="language-typescript">import &#039;reflect-metadata&#039;;

function LogTypes(target: any, propertyKey: string, descriptor: PropertyDescriptor) {

const types = Reflect.getMetadata(&#039;design:paramtypes&#039;, target, propertyKey);

const returnType = Reflect.getMetadata(&#039;design:returntype&#039;, target, propertyKey);

console.log(Método: ${propertyKey});

console.log(Tipos dos parâmetros:, types);

console.log(Tipo de retorno:, returnType);

return descriptor;

}

class Usuario {

@LogTypes

saudar(nome: string, idade: number): string {

return Olá ${nome}, você tem ${idade} anos;

}

}

const usuario = new Usuario();

usuario.saudar(&#039;João&#039;, 30);

// Output: Método: saudar, Tipos: [String, Number], Tipo de retorno: String</code></pre>

<h2>Decorators Prático: Validação e Autorização</h2>

<p>Decorators são especialmente úteis para validação e autorização em controladores. No mundo real, é comum validar dados de entrada ou verificar permissões antes de executar um método. Vamos criar decorators reutilizáveis que resolvem problemas comuns:</p>

<pre><code class="language-typescript">import &#039;reflect-metadata&#039;;

// Decorator para validar email

function ValidateEmail(target: any, propertyKey: string, descriptor: PropertyDescriptor) {

const método = descriptor.value;

descriptor.value = function(...args: any[]) {

const email = args[0];

if (!email.includes(&#039;@&#039;)) {

throw new Error(&#039;Email inválido&#039;);

}

return método.apply(this, args);

};

return descriptor;

}

// Decorator para verificar autenticação

function Autenticado(target: any, propertyKey: string, descriptor: PropertyDescriptor) {

const método = descriptor.value;

descriptor.value = function(...args: any[]) {

const usuarioLogado = (this as any).usuario;

if (!usuarioLogado) {

throw new Error(&#039;Usuário não autenticado&#039;);

}

return método.apply(this, args);

};

return descriptor;

}

class ServicoEmail {

usuario: string | null = &#039;joao@example.com&#039;;

@Autenticado

@ValidateEmail

enviarEmail(email: string, mensagem: string): void {

console.log(Email enviado para ${email}: ${mensagem});

}

}

const servico = new ServicoEmail();

servico.enviarEmail(&#039;maria@example.com&#039;, &#039;Olá!&#039;);</code></pre>

<h2>Decorators no NestJS: Aplicação Real</h2>

<p>NestJS é um framework Node.js que usa decorators extensivamente para criar aplicações modulares e escaláveis. Vamos criar um exemplo prático de um controlador com decorators de validação e autorização:</p>

<pre><code class="language-typescript">import { Controller, Get, Post, Body, Param, UseGuards } from &#039;@nestjs/common&#039;;

import { IsEmail, IsString } from &#039;class-validator&#039;;

class CriarUsuarioDto {

@IsString()

nome: string;

@IsEmail()

email: string;

}

// Guard customizado com decorator

import { Injectable, CanActivate, ExecutionContext } from &#039;@nestjs/common&#039;;

@Injectable()

class AdminGuard implements CanActivate {

canActivate(context: ExecutionContext): boolean {

const request = context.switchToHttp().getRequest();

return request.user?.role === &#039;admin&#039;;

}

}

@Controller(&#039;usuarios&#039;)

export class UsuariosController {

private usuarios: any[] = [];

@Get(&#039;:id&#039;)

obterUsuario(@Param(&#039;id&#039;) id: string) {

return this.usuarios.find(u =&gt; u.id === id);

}

@Post()

@UseGuards(AdminGuard)

criarUsuario(@Body() dto: CriarUsuarioDto) {

const novoUsuario = { id: Date.now().toString(), ...dto };

this.usuarios.push(novoUsuario);

return novoUsuario;

}

}</code></pre>

<p>NestJS fornece decorators para métodos HTTP (<code>@Get</code>, <code>@Post</code>), injeção de dependência (<code>@Injectable</code>), validação automática com <code>class-validator</code>, e guards para autorização. A biblioteca <code>class-transformer</code> complementa isso, permitindo transformar dados em instâncias de classes com validação integrada.</p>

<h2>Conclusão</h2>

<p>Decorators em TypeScript, combinados com reflection e metadata, são ferramentas poderosas para criar código limpo, reutilizável e auto-documentado. Eles permitem separar concerns como validação, autenticação e logging da lógica de negócio. No contexto do NestJS, tornam-se absolutamente essenciais para estruturar aplicações enterprise. O aprendizado de decorators é fundamental para dominar frameworks modernos e escrever código profissional em TypeScript. Pratique criando seus próprios decorators antes de usar os prontos, isso consolida o entendimento.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://www.typescriptlang.org/docs/handbook/decorators.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook: Decorators</a></li>

<li><a href="https://www.npmjs.com/package/reflect-metadata" target="_blank" rel="noopener noreferrer">reflect-metadata - npm</a></li>

<li><a href="https://docs.nestjs.com/" target="_blank" rel="noopener noreferrer">NestJS Documentation</a></li>

<li><a href="https://www.npmjs.com/package/class-validator" target="_blank" rel="noopener noreferrer">class-validator - npm</a></li>

<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">You Don&#039;t Know JS Yet: Scope &amp; Closures</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

Dominando Design Patterns em JavaScript: Factory, Singleton e Builder em Projetos Reais
Dominando Design Patterns em JavaScript: Factory, Singleton e Builder em Projetos Reais

O que são Design Patterns? Design Patterns são soluções comprovadas para prob...

Boas Práticas de Cluster e Worker Threads em Node.js: Aproveitando Múltiplos Núcleos para Times Ágeis
Boas Práticas de Cluster e Worker Threads em Node.js: Aproveitando Múltiplos Núcleos para Times Ágeis

O Problema de Performance no Node.js Node.js é single-threaded por padrão, o...

NestJS com TypeScript: Arquitetura Modular, DI e Guards na Prática
NestJS com TypeScript: Arquitetura Modular, DI e Guards na Prática

Arquitetura Modular no NestJS O NestJS foi construído com a modularidade como...