Decorators em TypeScript
Tags: typescript, tutorial, webdev, programming
Published: 2023-08-25 23:30:06

Os decorators são um recurso proposto para JavaScript e são adotados por TypeScript para adicionar anotações e uma sintaxe de metaprogramação para classes e membros de classes. Eles oferecem uma maneira de adicionar comportamentos adicionais a classes, métodos, propriedades, parâmetros ou acessadores.

## O que são decorators e como usá-los

Decorators são funções especiais que podem ser usadas para estender a funcionalidade de classes, métodos, propriedades e parâmetros. Eles são prefixados com `@` e podem ser anexados a várias declarações.

Para usar decorators em TypeScript, você precisa habilitar a opção `experimentalDecorators` em seu arquivo `tsconfig.json`.

```json
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}
```

## Exemplos práticos

### 1. Logging

Um decorator simples para registrar quando um método é chamado:

```typescript
function LogMethod(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
        console.log(`Chamado método ${propertyKey} com argumentos: ${JSON.stringify(args)}`);
        return originalMethod.apply(this, args);
    };

    return descriptor;
}

class MathOperations {
    @LogMethod
    add(x: number, y: number): number {
        return x + y;
    }
}

const math = new MathOperations();
math.add(2, 3);  // Log: Chamado método add com argumentos: [2,3]
```

### 2. Memoização

Memoização é uma técnica de otimização em que o resultado de uma função para um conjunto específico de entradas é armazenado, e se a mesma entrada ocorrer novamente, o resultado armazenado é retornado em vez de recalculá-lo.

```typescript
function Memoize(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    const cache = new Map<string, any>();

    descriptor.value = function (...args: any[]) {
        const cacheKey = JSON.stringify(args);
        if (cache.has(cacheKey)) {
            return cache.get(cacheKey);
        }
        const result = originalMethod.apply(this, args);
        cache.set(cacheKey, result);
        return result;
    };

    return descriptor;
}

class Fibonacci {
    @Memoize
    calculate(n: number): number {
        if (n < 2) return n;
        return this.calculate(n - 1) + this.calculate(n - 2);
    }
}
```

### 3. Validação com decorators

Podemos usar decorators para validar argumentos de métodos.

```typescript
function ValidateNonNull(target: Object, propertyKey: string, parameterIndex: number) {
    const originalMethod = target[propertyKey];

    target[propertyKey] = function (...args: any[]) {
        if (args[parameterIndex] == null) {
            throw new Error(`Argument at index ${parameterIndex} should not be null or undefined.`);
        }
        return originalMethod.apply(this, args);
    };
}

class UserService {
    createUser(@ValidateNonNull name: string) {
        // código para criar um usuário
    }
}
```

Ao usar o decorator acima, a função `createUser` lançará um erro se o nome fornecido for nulo ou indefinido.

## Conclusão

Os decorators em TypeScript oferecem uma poderosa ferramenta de metaprogramação que permite adicionar comportamentos adicionais ao código existente de maneira elegante e reutilizável. Seja para logging, memoização ou validação, os decorators tornam o código mais limpo e mais fácil de manter.