Como usar TypeScript decorators
TypeScript decorators são uma maneira prática e simples de adicionar funcionalidades extras a objetos sem modificar o código original. Eles podem ser aplicados a classes, métodos, propriedades e parâmetros, aprimorando anotações e metadados.
O que são TypeScript decorators e por que usá-los?
O princípio adotado por TypeScript decorators não é novo. Outras linguagens de programação oferecem recursos similares, como atributos em C#, Decorators em Python e anotações em Java. Decorators expandem a funcionalidade de um objeto sem modificar o código original. O TypeScript já tem utilizado essa abordagem há algum tempo. Embora a maioria dos navegadores ainda não suporte TypeScript decorators, vale a pena explorar essa abordagem e suas possibilidades
TypeScript decorators são usados para adicionar anotações e metadados adicionais a classes TypeScript e seus elementos. Eles são capazes de modificar não apenas classes, mas também métodos, propriedades, métodos de acesso e parâmetros. Esses últimos podem ser validados e seus valores recuperados, seu grande diferencial em relação ao equivalente JavaScript.
Sintaxe e funcionamento de TypeScript decorators
Ao adicionar decorators a um objeto TypeScript, você está tecnicamente invocando uma função TypeScript que pode ser executada sem alterar o código original. Isso aumenta a funcionalidade do código por mantê-lo limpo. A sintaxe básica de um TypeScript decorator é a seguinte:
@nomeDoDecoratortypescriptEssa função pode ser criada com dois ou três parâmetros. A sintaxe para a função com três parâmetros é:
function decoratorFunction(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Decorating ${propertyKey} of class ${target.constructor.name}`);
}
class MyClass {
@decoratorFunction
myMethod() {}
}typescriptEstes são os elementos do TypeScript decorators:
target: Refere-se ao objeto ao qual o decorator foi atribuído.propertyKey: É a string que contém o nome da classe à qual o decorator foi atribuído, seja um método ou atributo.descriptor: Contém informações sobre o objeto ao qual o decorator é aplicado. Entre os atributos estãovalue,writable,enumerableouconfigurable.
Aqui está a sintaxe de um TypeScript decorator com dois parâmetros:
function decoratorFunction(target: any) {
console.log(`Decorating ${target.name}`);
}
@decoratorFunction
class MyClass {}typescriptNesse caso, o decorator foi aplicado a uma classe.
Tipos de TypeScript decorators
Existem diferentes tipos de TypeScript decorators, cada um com suas características próprias:
- Class decorators
- Method decorators
- Property decorators
- Accessor decorators
- Parameter decorators
Class decorators: TypeScript decorators para classes
Para modificar as características de uma classe, como seu construtor, métodos ou propriedades, TypeScript decorators são uma ótima opção. O primeiro parâmetro recebido é o construtor, assim que você “decora” a classe com uma função. Observe abaixo um exemplo de código. Ele contém uma classe com propriedades privadas e públicas:
class Cliente {
private static userType: string = "Genérico";
private _email: string;
public nome: string;
public endereco: string = "";
public cidade: string = "";
public pais: string = "";
constructor(nome: string, email: string) {
this.nome = nome;
this._email = email;
}
static get tipoUsuario() {
return Cliente.userType;
}
get email() {
return this._email;
}
set email(novoEmail: string) {
this._email = novoEmail;
}
enderecoCompleto(): string {
return `${this.endereco}\n${this.cidade}\n${this.pais}`;
}
}
const c = new Cliente("ExemploCliente", "nome@exemplo.com");
c.endereco = "Rua Exemplo 2";
c.cidade = "São Paulo";typescriptNo próximo passo, usamos um TypeScript decorator para adicionar mais funcionalidades sem modificar o código original. Adicionamos o decorator @frozen à classe “Cliente”, impedindo alterações nos objetos após sua criação. Em algumas propriedades, usamos @required para indicar obrigatoriedade e @enumerable para listagens. Também usamos @deprecated para sinalizar entradas obsoletas. Primeiramente, definimos os decorators:
function frozen(constructor: Function) {
Object.freeze(constructor);
Object.freeze(constructor.prototype);
}
function required(target: any, propertyKey: string) {
// Lógica para Required Decorator
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
function deprecated(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.warn(`O método ${propertyKey} está obsoleto.`);
}typescriptApós aplicarmos TypeScript decorators, o código final fica assim:
@frozen
class Cliente {
private static userType: string = "Genérico";
@required
private _email: string;
@required
public nome: string;
public endereco: string = "";
public cidade: string = "";
public pais: string = "";
constructor(nome: string, email: string) {
this.nome = nome;
this._email = email;
}
@enumerable(false)
get userType() {
return Cliente.userType;
}
get email() {
return this._email;
}
set email(novoEmail: string) {
this._email = novoEmail;
}
@deprecated
enderecoCompleto(): string {
return `${this.endereco}\n${this.cidade}\n${this.pais}`;
}
}
const c = new Cliente("ExemploCliente", "nome@exemplo.com");
c.endereco = "Rua Exemplo 2";
c.cidade = "São Paulo";typescriptMethod decorators: TypeScript decorators para métodos
Você pode aplicar TypeScript decorators a métodos, exceto em arquivos de declaração, sobrecargas ou na palavra-chave declare. No exemplo a seguir, usamos @enumerable como decorator para o método getNome na classe “Pessoa”:
const enumerable = (value: boolean) => {
return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
propertyDescriptor.enumerable = value;
}
}
class Pessoa {
primeiroNome: string = "Julia";
ultimoNome: string = "Silva";
@enumerable(true)
getNome() {
return `${this.primeiroNome} ${this.ultimoNome}`;
}
}typescriptProperty decorators: TypeScript decorators para propriedades
TypeScript decorators aplicados a propriedades de uma classe têm dois parâmetros: a função do construtor da classe e o nome da propriedade. No exemplo abaixo, o decorator é usado para exibir o nome de uma propriedade (neste caso, o nome do cliente):
const printPropertyName = (target: any, propertyName: string) => {
console.log(propertyName);
};
class Cliente {
@printPropertyName
nome: string = "Julia";
}typescriptAccessor decorators: TypeScript decorators para métodos de acesso
Accessor decorators funcionam de maneira semelhante a Property decorators, mas têm um terceiro parâmetro adicional. Em nosso exemplo, é o Property descriptor de um cliente. Quando aplicamos um Accessor decorator, ele altera o valor do Property descriptor. O código abaixo mostra como mudar o valor booleano de enumerable:
const enumerable = (value: boolean
) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
descriptor.enumerable = value;
};
};typescriptAgora, aplicando o decorator, temos o seguinte código:
class Cliente {
primeiroNome: string = "Julia";
ultimoNome: string = "Silva";
@enumerable(true)
get nomeCompleto() {
return `${this.primeiroNome} ${this.ultimoNome}`;
}
}typescriptParameter decorators: TypeScript decorators para parâmetros
Parameter Decorators no TypeScript têm três parâmetros: a função do construtor da classe, o nome do método e o índice do parâmetro. Embora o decorator não permita alterar o parâmetro diretamente, ele é útil para validação. Por exemplo, você pode verificar o índice do parâmetro com o seguinte código:
function logParameter(target: Object, propertyKey: string, parameterIndex: number) {
console.log(`Decorating parameter ${parameterIndex} of ${propertyKey}`);
}typescriptAplicação do decorator de parâmetro:
class Exemplo {
testMethod(param0: any, @logParameter param1: any) {}
}typescriptIdeal para sites estáticos e outras aplicações: com o Deploy Now da IONOS, você se beneficia de uma configuração rápida, de um staging simples e de fluxos de trabalho perfeitamente ajustados. Encontre o modelo ideal para as suas necessidades.

