Decore seu código com decoradores de TypeScript

Mohan Ram Blocked Desbloquear Seguir Seguindo 26 de dezembro de 2018 Foto de Alex Loup no Unsplash

Decoradores introduz programadores para escrever a anotação de metadados que o ajudará a examinar seu código. Melhor caso de uso que você encontrar para decoradores, serão as preocupações transversais – Programação Orientada a Aspectos.

Na computação, a programação orientada a aspectos ( AOP ) é um paradigma de programação que visa aumentar a modularidade, permitindo a separação de interesses transversais . Isso é feito adicionando comportamento adicional ao código existente (um conselho) sem modificar o próprio código.

Amostras de decoradores – uso do decorador de nível de classe e método

Acima do código – ilustra como os decoradores são declarativos. Vamos cobrir os decoradores em detalhes como abaixo

  1. O que é decorador? e sua finalidade, tipos
  2. Assinaturas dos decoradores
  3. Decorador de Método
  4. Decorador de propriedades
  5. Decorador de Parâmetros
  6. Decorador Accessor
  7. Decorador de Classes
  8. Generalize decoradores com Factory Decorator
  9. API de reflexão de metadados
  10. Conclusão

O que é decorador e sua finalidade, tipos

Um decorador é um tipo especial de declaração que pode ser anexado a uma declaração de classe, método, acessador, propriedade ou parâmetro.

Os decoradores usam o formato @expression expression , em que a expression deve ser avaliada para uma função que será chamada em tempo de execução com informações sobre a declaração de decoração.

Ele serve ao propósito de adicionar metadados ao código existente de maneira declarativa.

Tipos de decoradores e sua prioridade de execução são

  1. Decorador de classes – Prioridade 4 (Instância de objeto, estática)
  2. Decorador de Método – Prioridade 2 (Instância de Objeto, Estática)
  3. Acessor ou Decorador de Propriedade – Prioridade 3 (Instância de Objeto, Estática)
  4. Parâmetro Decorador – Prioridade 1 (Instância do Objeto, Estático)

Nota – Se um decorador é aplicado para os parâmetros do construtor de classe, então a prioridade para esses será 1. parâmetro, 2. método, 3. acessador ou decorador de propriedade – então 4. Construtor de parâmetro de construtor será executado seguido por 5. decorador de classe.

Ordem de avaliação e execução do decorador

No código acima, vemos que um decorador f e g retorna uma outra função que é uma função decorador. f e g são chamados de fábricas de decoradores

As fábricas de decoradores ajudam o consumidor a passar os argumentos para que o decorador possa fazer uso.

A ordem de avaliação é de cima para baixo e a execução é de baixo para cima.

Assinaturas dos decoradores

Assinaturas dos decoradores

Decorador de Método

Da assinatura acima, a função de decorador de método espera três argumentos:

  1. target – protótipo do objeto atual ie – se Employee é um objeto, Employee.prototype
  2. propertyKey – nome do método
  3. descritor – descritor de propriedade do método ie – Object.getOwnPropertyDescriptor(Employee.prototype, propertyKey)

exemplo de decorador de método

o código acima deve ser auto-explicativo – Vamos ver como o código JavaScript compilado se parece

resultado compilado

Vamos começar a analisar a função Employee – os parâmetros de name inicialização do construtor e o método de greet anexado ao protótipo

__decorate([logMethod],Employee.prototype,”greet”)

Este é o método genérico gerado pelo TypeScript para lidar com a chamada de função do decorador com o respectivo argumento baseado no tipo de decorador.

Essa função ajuda a introspectar a chamada do método e preparar o caminho para o desenvolvedor lidar com as questões de corte transversal, como registro, memorização e aplicação de configurações, como enumeráveis, etc.

No exemplo – nós apenas imprimimos a função chamada com seu argumento + resposta.

Nota – leia os comentários detalhados no método __decorate para entender os internos

Decorador de propriedades

A função de decorador de propriedade espera dois argumentos:

  1. target – protótipo do objeto atual ie – se Employee é um objeto, Employee.prototype
  2. propertyKey – nome da propriedade

exemplo de decorador de propriedade

No código acima, introspectamos a acessibilidade da propriedade no decorador e o código compilado como abaixo.

resultado compilado

Decorador de Parâmetros

A função de decorador de parâmetros espera três argumentos:

  1. target – protótipo do objeto atual ie – se Employee é um objeto, Employee.prototype
  2. propertyKey – nome do método
  3. índice – posição do parâmetro no array de argumentos

exemplo de decorador de parâmetros

No código acima, coletamos todo o índice ou posição dos parâmetros decorados dos métodos como metadados e anexados ao protótipo do objeto. O código compilado está abaixo.

resultado compilado

Como vimos anteriormente, a função __decorate , A função __param , retorna um decorador que envolve o decorador de parâmetros.

Como podemos ver quando o decorador de parâmetros é chamado, seu retorno é ignorado. Isto significa que quando a função __decorate é chamada, seu retorno não será usado para sobrescrever o parâmetro.

Esta é a razão pela qual os decoradores de parâmetros não retornam.

Decorador Accessor

Acessor não é nada, mas a parte getter e setter da propriedade na declaração de classe.

Um Decorador Accessor é declarado imediatamente antes de uma declaração de acessador. O decorador de acessador é aplicado ao Descritor de Propriedade para o acessador e pode ser usado para observar, modificar ou substituir as definições de um acessador.

exemplo de decorador de acessor

No código acima, nós definimos dois name acessor e salary uma vez que configuramos a parte de enumeração via decorator. Objeto age de acordo. Saída é o name fará parte da enumeração e o salary não é.

Nota: O TypeScript não permite a decoração do acessador get e set para um único membro. Em vez disso, todos os decoradores do membro devem ser aplicados ao primeiro acessador especificado na ordem do documento. Isso ocorre porque os decoradores aplicam-se a um Descritor de propriedades , que combina o acessador get e set , não cada declaração separadamente.

O código de compilação está abaixo

resultado compilado

Decorador de Classes

O decorador de classes é aplicado ao construtor da classe e pode ser usado para observar, modificar ou substituir uma definição de classe.

exemplo de decorador de classe

O decorador acima declara uma variável chamada original e define seu valor para o construtor da classe que está sendo decorada.

Então, uma função de utilidade chamada construct é declarada. Esta função nos permite criar instâncias de uma classe.

Em seguida, criamos uma variável chamada f que será usada como o novo construtor. Essa função invoca o construtor original e também registra no console o nome da classe que está sendo instanciada. Aqui é onde vamos adicionar algum comportamento extra ao construtor original .

O protótipo do construtor original é copiado para o protótipo de f para garantir que o operador instanceof funcione como esperado quando criamos uma nova instância de um Employee.

Quando o novo construtor estiver pronto, precisamos apenas retorná-lo para concluir a implementação do decorador de classes.

Agora que o decorador está pronto, ele registrará no console o nome de uma classe toda vez que for instanciado

Código compilado é.

resultado compilado

Na versão compilada, notamos duas coisas diferentes,

  1. Se você ver os argumentos passados para __decorate seus dois – matriz de decoradores e a função de construtor
  2. O compilador TypeScript está usando o retorno de __decorate para substituir o construtor original.

Esta é a razão pela qual os decoradores de classes devem retornar uma função de construtor .

Generalize decoradores com Factory Decorator

Já que cada tipo de decorador tem sua própria assinatura para invocar. Podemos usar a fábrica decoradora para generalizar a invocação da chamada do decorador

decorador de log genérico usando fábrica decorador

API de reflexão de metadados

Para organizar os metadados de maneira padrão, a API de reflexão de metadados pode ser usada [ie – Reflect – builtin object]

O reflexo do nome é usado para descrever o código que é capaz de inspecionar outro código no mesmo sistema (ou em si).

A reflexão é útil para vários casos de uso (Composição / Injeção de Dependência, Asserções de Tipo de Tempo de Execução, Teste).

amostras de APIs de reflexão de metadados [ a biblioteca reflect-metadata é usada para reflexão]

No exemplo acima, usamos a chave de design de metadados [ex: design:type ] . Por enquanto – existem apenas três disponíveis:

  • Metadados de tipo usam o design:type chave de metadados design:type .
  • Metadados de tipo de parâmetro usam o design:paramtypes chave de metadados design:paramtypes .
  • Metadados de tipo de retorno usam o design:returntype chave de metadados design:returntype .

Com a ajuda da reflexão, poderíamos encontrar as seguintes coisas em tempo de execução.

  • O nome da entidade.
  • O tipo da entidade.
  • Quais interfaces são implementadas pela entidade.
  • O nome e os tipos das propriedades da entidade.
  • O nome e os tipos dos argumentos do construtor da entidade.

Conclusão

  • Decoradores são apenas funções que ajudam a examinar o código, anotar e modificar classes e propriedades em tempo de design.
  • Decoradores são um padrão proposto para ECMAScript 2016 por Yehuda Katz.
  • Podemos passar argumentos do usuário para o decorador através de fábricas de decoradores .
  • Existem 4 tipos de decoradores. Eles são – Class, Method, Property ou Accessor, Parameter Decorators .
  • A API de Reflexão de Metadados ajuda a adicionar as informações de metadados de maneira padrão a um objeto e ajuda a obter as informações de tipo de design no tempo de execução .

Você pode encontrar todas as amostras neste Repositório Git . Obrigado pela leitura!