Uma introdução prática à Decorators no TypeScript
Tags: javascript, decorators, typescript
Published: 2020-03-19 12:27:01

---
title: Uma introdução prática à Decorators no TypeScript
published: true
date: 2020-03-19 12:22:30 UTC
tags: javascript,decorators,typescript
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1024/1*sRPCWiqE2AWYiPyRnu81gg.jpeg)<figcaption>Photo by <a href="https://unsplash.com/@flowforfrank?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ferenc Almasi</a> on <a href="https://unsplash.com/s/photos/decorator?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption>

Os _decorators_ são um dos recursos mais poderosos oferecido pelo TypeScript, tendo como um dos principais objetivos ampliar funcionalidades de classes e métodos de forma simples e limpa. Atualmente, os _decorators_ são uma proposta de estágio 2 para JavaScript e estão disponíveis como um recurso experimental no TypeScript. Mesmo sendo um recurso experimental, eles já estão presentes em grandes projetos de código aberto, como o Angular e Inversify.

Por ser um recurso experimental, para ser possível utilizar no TypeScript, é necessário habilitar no tsconfig.json:

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

Ou pela linha de comando:

```
tsc --target ES5 --experimentalDecorators
```

Mesmo que inicialmente os _decorators_ possam parecer mágicos, eles são simples de se entender e fáceis de se criar.

### Mas afinal, o que é um decorator?

O site do TypeScript descreve como:

> “Um Decorator é um tipo especial de declaração que pode ser anexada a uma declaração de classe, método, acessador, propriedade ou parâmetro.”

Essa definição pode não explicar muito o que um _decorator_ realmente representa. Eu prefiro definir como “uma declaração especial para adicionar funcionalidades extras a uma declaração de classe, método, acessador, propriedade ou parâmetro”.

Você pode ter visto em algum projeto a utilização de _decorators_, eles utilizam o formato @expression, onde o valor expression representa uma função que fará as modificações as classes, métodos, acessadores, propriedades ou parâmetros.

Para se criar um _decorator_ é bem simples. Como já previamente explicado, os _decorators_ são apenas funções, essas funções são chamadas em tempo de execução. Um exemplo bem simples é criarmos uma função log que irá realizar um console.log no alvo em que ele for utilizado, ficando desta maneira:

{% gist https://gist.github.com/omarkdev/7e49388a8e4e78bf03300cdce3a7e7a1 %}

Pode ser que em certas situações pode ser necessário você customizar como um _decorator_ é aplicado à uma declaração. Para isso, é necessário criar um **_Decorator Factory_** , que é uma função que retorna a expressão que será executada. Seguindo o mesmo exemplo, imagine que agora você queira adicionar um prefixo estático nos logs, o resultado seria algo assim:

{% gist https://gist.github.com/omarkdev/a657f8831ed299ba7cb477c0ec8043f5 %}

Como é possível analisar, agora ao invés de recebermos o alvo como parâmetro, recebemos o parâmetro que informamos e temos que retornar uma função, que será executada.

### Tipos de decorators

Ao se desenvolver _decorators_ é importante saber que existem vários tipos, esses tipos são determinados pelo alvo em que está sendo aplicado, sendo que cada tipo tem suas particularidades e assinaturas diferentes. Atualmente os tipos existentes são:

1. Class Decorator.
2. Property Decorator.
3. Method Decorator.
4. Accessor Decorator.
5. Parameter Decorator.

#### Class Decorator

A maneira mais simples de se começar a entender os _decorators_ é começar desenvolvendo para classes. Um _decorator_ para classe deve ser declarado antes da declaração da classe. Esse _decorator_ recebe um único parâmetro que é o construtor da classe alvo.

{% gist https://gist.github.com/omarkdev/4e550681929666e36b412060553a2d23 %}

Caso o _decorator_ retorne um valor, ele substituirá a declaração de classe pelo valor fornecido, que deve ser um construtor. Dessa maneira, diferente do exemplo acima, podemos aplicar mudanças diretas à classe, ao invés de apenas no protótipo da classe.

{% gist https://gist.github.com/omarkdev/3e66db24a2eb92b70efe7dc8149a913e %}

É importante ressaltar que caso você decida retornar um construtor, você deve manter a mesma assinatura do alvo.

Você perceberá no decorrer do aprendizado, que esse tipo de _decorator_ é o mais generalista, pois nele você pode ter acesso à classe inteira, ao invés de pequenas partes do objeto.

#### Property Decorator

Um _decorator_ de propriedade deve ser declarado antes da declaração da propriedade. Dessa vez, o _decorator_, recebe 2 parâmetros, target e key. O parâmetro target é o protótipo da classe em que está sendo aplicado o _decorator_, já o parâmetro key é o nome da propriedade da classe em que está sendo aplicado o _decorator_.

{% gist https://gist.github.com/omarkdev/e2bceace35b92477e744094e66129c92 %}

Com esse pequeno exemplo, foi mostrado na tela Task {} 'title', que representa o protótipo da classe e o nome da propriedade.

Um ponto interessante e importante de se analisar, como já foi dito, recebemos como parâmetro o protótipo da classe e não sua instância, sabendo disso é possível ver no exemplo que o _decorator_ foi executado mesmo sem instanciarmos a classe, isso por que o _decorator_ é chamado no tempo de execução do arquivo. Isso deve ser levado em consideração na hora de se criar seus _decorators_ já que você não terá uma chamada no _decorator_ a cada vez que instanciar a classe.

O interessante desse tipo de _decorator_ é a possibilidade de aplicar mudanças de comportamento nas propriedades.

{% gist https://gist.github.com/omarkdev/00d2dfd000ad5f962c495e96531022d4 %}

No exemplo, criamos um _decorator_ chamado logProperty que tem como objetivo fazer um console.log toda vez que a propriedade tiver seu valor alterado ou for acessada. Para saber o que acontece na propriedade, utilizamos os getters e setters do próprio JavaScript.

#### Method Decorator

Para muitos esse é o tipo de _decorator_ mais útil oferecido pelo TypeScript. Um _decorator_ para métodos deve ser declarado antes da declaração do método. Ao se utilizar um _method decorator_ recebemos 3 parâmetros. O primeiro parâmetro é o target que é protótipo da classe, igual ao que vimos no _property decorator_. O segundo parâmetro é o propertyKey que é o nome do método em que estamos aplicando. Já o último é o propertyDescriptor, que é um conjunto de propriedades que definem uma propriedade de um objeto em JavaScript, neste objeto podemos ter acesso a propriedades como: configurable, enumerable, value e writable, além de get e set. Tendo acesso nesses 3 parâmetros, somos capazes de realizar quase qualquer operação em cima de nossos métodos.

Vamos imaginar um cenário onde temos um método changePassword em uma classe User e queremos alterar o enumerable deste método através de um decorator para que esse método não apareça na hora de percorrer as propriedades existentes na classe.

{% gist https://gist.github.com/omarkdev/d449ec894ab198a8f3ed675f73cf2c51 %}

Neste simples exemplo, será mostrado na tela name e changePassword. Como queremos alterar o enumerable para o valor false deste método para não mostrar na tela, basta alteramos a propriedade dentro do nosso propertyDescriptor.

{% gist https://gist.github.com/omarkdev/07d9ee26214637c6bfc2ce6a2ddb15f7 %}

Agora será mostrado na tela apenas name.

Esse tipo de _decorator_ é extremamente útil quando queremos aplicar mudanças no comportamento dos nossos métodos e como temos acesso a quase tudo que representa o método, se torna muito simples aplicarmos as mudanças que queremos.

#### Accessor Decorator

Os accessor _decoratos_ são os mesmos que os _method decorators_, mas são aplicados aos métodos _setter_ ou _getter._

{% gist https://gist.github.com/omarkdev/72ae760c3eeafdb714f566134e285da1 %}

É importante entender que o TypeScript não permite aplicar um _decorator_ a ambos os acessadores de um único membro. Em vez disso, deve ser aplicado o _decorator_ ao primeiro acessador especificado na ordem do objeto.

{% gist https://gist.github.com/omarkdev/45df16aeeaa1085670dc04df830cff53 %}

#### Parameter Decorator

Por último, mas não menos importante, temos os _parameter decorators_. Um _parameter decorator_ deve ser declarado antes da declaração de um parâmetro. Esse decorator recebe 3 parâmetros. O primeiro, como na maioria dos _decorators_ que já vimos é o target que é o protótipo da classe. O segundo é o propertyKey que é o nome do método que contém o parâmetro estamos trabalhando, bem semelhante ao que ja vimos no _method decorator_. Já o último parâmetro, é o parameterIndex que é o número da posição do parâmetro na função, lembrando que começa a partir do 0.

{% gist https://gist.github.com/omarkdev/b16056e95fb9f79e7d4cfb586b583d01 %}

Dessa maneira como estamos construindo os nossos _decorators_, só é possível analisar o objeto e o método, qualquer alteração necessária no comportamento requer o uso do [reflect-metadata](https://www.typescriptlang.org/docs/handbook/decorators.html#metadata) (que é um assunto para outro post).

### Quando usar

É comum quando estamos aprendendo algo novo entendermos como algo funciona mas dificilmente conseguiremos enxergar cenários para aquele aprendizado. Para alguns, não é diferente ao começar a aprender a trabalhar com os _decorators_.

Os _decorators_ são extremamente úteis quando devemos adicionar ou alterar comportamento de nossos alvos através de meta-programação. Quando temos algo que pode ser considerado genérico, mas que pode ser reutilizado em vários lugares no objetivo de facilitar alguma mudança em cima do alvo, talvez seja uma ótima situação para se utilizar.

Ao se começar a pensar na criação de nossos próprios _decorators_ podemos ver que um grande benefício é a reutilização, porém mesmo que isso seja uma verdade, devemos tomar muito cuidado para não acabar criando coisas extremamente complexas com várias responsabilidades e efeitos colaterais.

Espero que isso te ajude de alguma forma.

**Twitter** : [_https://twitter.com/omarkdev_](https://twitter.com/omarkdev)  
**Github** : [_https://github.com/omarkdev_](https://github.com/omarkdev)

* * *