Emulando recursos do TypeScript em JavaScript
O objetivo desse post é demonstrar como o TypeScript pode servir como fonte de inspiração para escrevermos um código menos verboso e fácil de manter em JavaScript. Começaremos primeiro com uma visão geral sobre a linguagem TypeScript.
Sobre a linguagem TypeScript
O TypeScript é um superset do JavaScript que fornece principalmente tipagem estática opcional, classes e interfaces. Um dos grandes benefícios é permitir que IDEs forneçam um ambiente mais rico para detectar erros comuns à medida que escrevemos nosso código.
Agora que já temos uma ideia desta linguagem, vejamos dois recursos interessantíssimos que ela oferece. O primeiro deles é um atalho para definição de propriedades de classe.
Atalho para definição de propriedades da classe
Em TypeScript, temos a seguinte declaração de classe:
class Conta {
private _titular: string;
private _banco: string;
private _agencia: string;
private _numero: string;
constructor(
titular: string,
banco:string,
agencia: string,
numero: string) {
this._titular = titular;
this._banco = banco;
this._agencia = agencia;
this._numero = numero;
}
// métodos acessadores e alteradores omitidos
}
Cada parâmetro recebido no constructor
equivale aos valores das propriedades this._titular
, this._banco
, this._agencia
e this._numero
. O programador terá que atribuir cada parâmetro na propriedade equivalente. Todavia, é possível simplificar a declaração desta forma:
class Conta {
constructor(
private _titular: string,
private _banco: string,
private _agencia: string,
private _numero: string) {}
// métodos acessadores e alteradores omitidos
}
Muito mais enxuta não?
Vejamos a mesma classe utilizando JavaScript:
class Conta {
constructor(titular, banco, agencia, numero) {
this._titular = titular;
this._banco = banco;
this._agencia = agencia;
this._numero = numero;
}
// métodos acessadores e alteradores omitidos
}
Em JavaScript, não há modificadores de acesso muito menos tipagem estática. Porém, será que podemos simplificar o constructor
desta classe para escrevermos menos como na versão utilizando TypeScript? Sim, podemos:
class Conta {
constructor(_titular, _banco, _agencia, _numero) {
Object.assign(this, { _titular, _banco, _agencia, _numero});
}
// métodos acessadores e alteradores omitidos
}
A solução acima utilizou dois recursos da linguagem. O primeiro, Object.assign
que permite criar um objeto ou modificar um já existente. No exemplo anterior, estamos modificando a própria instância da classe Conta
passando this
como primeiro parâmetro para Object.assign
.
O segundo parâmetro é um objeto no formato literal utilizando uma sintaxe abreviada que terá suas propriedades copiadas para a instância da classe Conta
. A sintaxe literal abreviada é possível quando a propriedade do objeto tem o mesmo nome da variável que contém o valor que a propriedade receberá.
Em suma, a declaração abreviada
Object.assign(this, { _titular, _banco, _agencia, _numero});
Equivale a declação não abreviada:
Object.assign(this, {
_titular: _titular,
_banco: _banco,
_agencia: _agencia,
_numero: _numero});
Não conseguimos uma sintaxe tão enxuta como no TypeScript, mas ao tentarmos perseguir sintaxe semelhante acabamos simplificando nosso código JavaScript.
Vejamos outro recurso do TypeScript a seguir.
Parâmetros obrigatórios
Ainda no contexto da classe Conta
na versão em TypeScript, somos obrigados a passar todos os parâmetros do constructor
ou teremos um erro de compilação:
class Conta {
constructor(
private _titular: string,
private _banco: string,
private _agencia: string,
private _numero: string) {}
// métodos acessadores e alteradores omitidos
}
// não compila
// Não passou o restante dos parâmetros do constructor
const conta = new Conta('Flávio');
Em JavaScript, podemos conseguir comportamento semelhante fazendo um uso não usual de default parameter
, parâmetro padrão. O valor padrão no constructor
da classe será uma função que lançará sempre uma exceção. Nesse contexto, se qualquer parâmetro for omitido, um erro em tempo de execução (runtime) será exibido:
function obrigatorio(campo) {
throw new Error(`${campo} é obrigatório`);
}
class Conta {
constructor(
_titular= obrigatorio('titular'),
_banco= obrigatorio('banco'),
_agencia= obrigatorio('agência'),
_numero= obrigatorio('número')
) {
Object.assign(this, { _titular, _banco, _agencia, _numero });
}
// métodos acessadores e alteradores omitidos
}
// lança a exceção!
const conta = new Conta('Flávio');
Diferente do TypeScript que exibiria um erro em tempo de compilação a solução anterior exibirá um error em rutime, ou seja, apenas quando nossa aplicação estiver rodando. No entanto, é uma maneira interessante de tornarmos obrigatórios os parâmetros do constructor
da classe com menos esforço.
Conclusão
Não é possível implementar os recursos do TypeScript que vimos neste post diretamente na linguagem JavaScript, todavia eles e outros recursos podem servir de inspiração para que desenvolvedor JavaScript escreva um código cada vez melhor.
Esses e outros truques você encontra no livro Cangaceiro JavaScript: Uma aventura no sertão da programação.