Alura > Cursos de Front-end > Cursos de JavaScript > Conteúdos de JavaScript > Primeiras aulas do curso TypeScript na prática: implemente um projeto completo com TypeScript e módulos

TypeScript na prática: implemente um projeto completo com TypeScript e módulos

JavaScript vs TypeScript - Apresentação

Olá, pessoa! Boas-vindas a esse curso de TypeScript, em que você será introduzido aos fundamentos da linguagem criando uma aplicação para nosso cliente Bytebank. Meu nome é Jhonatan Jacinto, mas pode me chamar de Jhota, e serei seu instrutor ao longo dessa jornada!

Audiodescrição: Jhonatan é um homem negro, de cabelo curto cacheado, com tatuagens no pescoço e um piercing na sobrancelha direita. Ele veste uma camisa cinza-escura e uma jaqueta de couro preta, e está sentado em uma cadeira preta, em frente a uma parede preta com uma estante preta repleta de livros. À direita do instrutor, há um piano digital.

O que iremos aprender?

A aplicação que será desenvolvida faz registro de transações em uma conta do Bytebank. Utilizando o formulário de novas transações, a pessoa usuária pode registrar transferências, fazer depósitos, fazer pagamentos de boleto, ou qualquer outra ação que determinarmos na aplicação.

Cada operação irá resultar em uma influência no saldo da aplicação e também no registro de transferências do extrato, no menu lateral à direita.

Na aplicação, veremos:

Vamos explorar os tipos existentes, isto é, os type alias, e aprenderemos a configurar uma enum, entendendo para que ela serve.

Fica o nosso convite para que você mergulhe nessa jornada e explore o fantástico mundo do TypeScript comigo! Vamos lá?

JavaScript vs TypeScript - Solução com JavaScript

Uma vez configurado o ambiente e feitos os ajustes necessários do VS Code, visualizando a aparência da nossa aplicação, podemos focar nos requisitos dela e entender como implementar primeiramente em JavaScript. Mas por quê?

Precisamos justificar o uso do TypeScript. Podemos desenvolver uma aplicação com JavaScript, mas veremos que, ao longo do processo de desenvolvimento, é possível encontrar alguns problemas que o TypeScript irá resolver.

Então, primeiro iremos desenvolver nossa solução com o JavaScript e observar o funcionamento da aplicação, e depois entenderemos nos detalhes os pontos onde ela falha e podemos resolver com o TypeScript.

Solução com JavaScript

Configurando a interface

Primeiramente, vamos alterar o título "Olá, Fabiana! :)" para "Olá, Joana! :)", seguindo o padrão do nosso projeto.

<h2>Olá, Joana! :)</h2>

Em seguida, na pasta do projeto, criaremos uma pasta chamada "js", onde vamos colocar toda a lógica do JavaScript necessária para fazer a aplicação funcionar.

Para começar nosso código, vamos conhecer os requisitos. Na pasta do projeto, temos um arquivo chamado Requisitos.txt, que lista algumas características que nossa aplicação precisa ter.

* Cada transação realizada no sistema deve possuir SOMENTE as seguintes informações:
  1) Data da Transação (Date)
  2) Tipo de Transação (Depósito, Transferência, Pagamento de Boleto)
  3) Valor da Transação (valor maior que zero)

* Sempre que a transação for do tipo DEPÓSITO, o valor da transação deve ser adicionado ao saldo da conta.
* Sempre que a transação for do tipo TRANSFERÊNCIA ou PAGAMENTO DE BOLETO, o valor da transação deve ser subtraído do saldo da conta.
* O saldo deve sempre ser atualizado na tela da aplicação a cada transação realizada.

Sabendo disso, vamos criar na pasta "js" um arquivo que inicialmente chamaremos de bytebank.js, que irá conter a lógica inicial gerenciando todos os elementos da tela.

No arquivo index.html, antes do fechamento da tag <body>, vamos importar o <script>, cujo src será o arquivo bytebank.js da pasta "js".

<script src="js/bytebank.js"></script>

Coletando e exibindo o saldo

Nós precisamos coletar sempre as informações do formulário de nova transação, e ao coletá-las, precisamos registrar os dados na tela. Além disso, precisamos exibir o saldo da conta.

Vamos encontrar essas informações no código HTML. A partir da linha 46, temos o formulário de transação (<form>) na <section> de classe block-nova-transacao.

<form action="" method="post" novalidate>
    <div class="campo">
        <select name="tipoTransacao" id="tipoTransacao" class="campo-input" required>
            <option value="">Selecione o tipo de transação</option>
            <option value="Depósito">Depósito</option>
            <option value="Transferência">Transferência</option>
            <option value="Pagamento de Boleto">Pagamento de Boleto</option>
        </select>
    </div>
    <div class="campo">
        <label for="valor">Valor:</label><br>
        <input type="number" name="valor" id="valor" class="campo-input" placeholder="0,00" step=".01" min="0" required />
    </div>
    <div class="campo">
        <label for="data">Data:</label><br>
        <input type="date" name="data" id="data" class="campo-input" placeholder="dd/mm/aaaa" required />
    </div>
    <div class="campo">
        <button type="submit" class="btn">
            Concluir transação
        </button>
    </div>
</form>

A partir da linha 27, temos a <section> de classe block-saldo, bloco que contém as informações de saldo. Essas informações específicas ficam no <span> de classe valor.

<span class="valor">R$ 2.500,00</span>

Sabendo disso, temos os locais onde vamos colocar cada informação.

Nosso primeiro passo será criar uma variável chamada saldo no arquivo bytebank.js, e definir um saldo qualquer inicialmente para trabalharmos, por exemplo, 3000.

let saldo = 3000;

Em seguida, precisamos exibir esse saldo na interface, conforme indicado como requisito no arquivo Requisitos.txt ("O saldo deve sempre ser atualizado na tela da aplicação a cada transação realizada."). Se nenhuma transação acontecer, assim que acessarmos a conta, precisaremos visualizar o saldo da mesma forma.

Vamos começar coletando o elemento que representa o saldo na tela.

Criaremos a constante elementoSaldo no arquivo bytebank.js, que será igual a document seguido do método querySelector(). Com isso, selecionaremos um elemento de document.

const elementoSaldo = document.querySelector();

Sabemos que o elemento desejado está dentro da <section> de classe block-saldo, e possui uma classe chamada valor. Também temos a opção de pesquisar pela classe saldo-valor, da <div> que contém o elemento, junto à classe valor, tag específica do saldo.

Entre os parênteses do método querySelector(), vamos selecionar os elementos .saldo-valor e .valor.

const elementoSaldo = document.querySelector(".saldo-valor .valor");

Logo abaixo, vamos atualizar o elemento adicionado digitando elementoSaldo.textContent, que será igual a saldo.

elementoSaldo.textContent = saldo;

Feito isso, vamos retornar à aplicação no navegador. Ao atualizar, teremos o campo de saldo atualizado, com o valor de 3.000.

Você irá notar que esse valor não é exibido com o cifrão, no formato de moeda correto, mas iremos corrigir isso aos poucos.

O mais importante nessa etapa é o seguinte: se o valor da variável saldo for alterado e pedirmos para a aplicação exibir o novo valor, ele será puxado corretamente.

Coletando os dados da nova transação

Agora precisamos coletar os dados da nova transação. Conforme os requisitos, sempre que for feita uma transação, é necessário registrá-la e atualizar o saldo. Para isso, precisamos coletar o formulário, que está dentro do bloco block-nova-transacao no código HTML.

Na linha 6 do arquivo bytebank.js, vamos declarar uma constante chamada elementoFormulario, que será igual ao método document.querySelector() utilizando a classe block.nova-transacao form, pois não queremos o bloco inteiro, apenas o formulário.

const elementoFormulario = document.querySelector(".block-nova-transacao form");

Logo abaixo, vamos digitar a constante elementoFormulario seguida de um ouvinte de evento, ou seja, o método addEventListener(). Ele irá conter submit, para que sempre que for submetido o formulário, termos acesso às informações contidas nele.

Entre os parênteses da função, também teremos uma função anônima (function () {}). Entre as chaves dessa função, passaremos um objeto de evento (event) para o método preventDefault().

Nos parênteses da função anônima, vamos receber os dados da variável event.

elementoFormulario.addEventListener("submit", function (event) {
    event.preventDefault();
});

Com o método preventDefault(), temos o seguinte: o comportamento padrão de um formulário é que, ao ser submetido, seja recarregada a página; nós queremos que o formulário seja submetido sem esse recarregamento, então o método previne o comportamento padrão do formulário.

Dessa forma, a página não será recarregada, mas ainda assim teremos acesso aos dados do evento, para a coleta das informações postadas pelo formulário.

Feita a postagem dos dados, precisamos saber se o formulário está válido, se todos os campos com o atributo required foram preenchidos. Para isso, vamos adicionar uma condicional if, contendo entre parênteses o elementoFormulario seguido do método checkValidity().

Vamos adicionar uma exclamação antes de elementoFormulario para indicar que se esse trecho for falso, o formulário estará inválido. Caso seja inválido, exibiremos um alerta (alert()) dizendo "Por favor, preencha todos os campos da transação".

Por fim, usaremos a palavra-chave return abaixo, para que o processamento da função ligada ao formulário não continue.

if (!elementoFormulario.checkValidity()) {
    alert("Por favor, preencha todos os campos da transação!");
    return;
}

Resultado do arquivo bytebank.js:

let saldo = 3000;

const elementoSaldo = document.querySelector(".saldo-valor .valor");
elementoSaldo.textContent = saldo;

const elementoFormulario = document.querySelector(".block-nova-transacao form");
elementoFormulario.addEventListener("submit", function (event) {
    event.preventDefault();
    if (!elementoFormulario.checkValidity()) {
        alert("Por favor, preencha todos os campos da transação!");
        return;
    }
});

Conclusão

Agora vamos retornar ao navegador para fazer um teste rápido:

JavaScript vs TypeScript - Objeto nova transação

Vamos retornar ao código e dar continuidade ao processo. Nesse momento, precisamos coletar os dados de cada elemento (tipo de transação, valor, e data) para registrar a transação.

Objeto nova transação

Coletando os dados da transação

No arquivo bytebank.js, ainda entre as chaves da função anônima, vamos adicionar uma constante chamada inputTipoTransacao, que será igual ao elementoFormulario seguido do método querySelector(), que terá o ID #tipoTransacao.

const inputTipoTransacao = elementoFormulario.querySelector("#tipoTransacao");

Coletado esse elemento, vamos fazer o mesmo processo para o valor, agora declarando a constante inputValor e o ID #valor para o método querySelector(). Em seguida, faremos o mesmo para a data, então teremos a constante inputData e o ID #data.

const inputValor = elementoFormulario.querySelector("#valor");
const inputData = elementoFormulario.querySelector("#data");

Agora vamos coletar os valores de cada um dos elementos. Para isso, logo abaixo, vamos declarar com let uma variável chamada tipoTransacao, que irá receber o valor contido no elemento, então a variável será igual a inputTipoTransacao.value.

let tipoTransacao = inputTipoTransacao.value;

O mesmo será feito para o valor e para a data:

let valor = inputValor.value;
let data = inputData.value;

Construindo o objeto de transação

O próximo passo é construir o objeto que irá representar uma nova transação e que deve conter apenas essas informações. Esse objeto será chamado de novaTransacao e irá conter tipoTransacao recebendo a variável tipoTransacao, valor recebendo valor, e data recebendo data.

const novaTransacao = {
    tipoTransacao: tipoTransacao,
    valor: valor,
    data: data
}

Dessa forma, teremos o objeto representando a nova transação e podemos exibi-lo no console para garantir que esteja tudo correto:

console.log(novaTransacao);

Feito isso, podemos reiniciar o formulário na linha abaixo com o método reset(), para indicar que, uma vez coletadas as informações, queremos limpar o formulário inteiro. Assim, a pessoa usuária poderá inserir os dados de uma nova transação quando quiser.

elementoFormulario.reset();

Vamos fazer um teste na aplicação. Com o navegador aberto, iremos teclar "F12" para abrir as ferramentas de Dev (DevTools). Em seguida, vamos preencher o formulário com os seguintes valores, por exemplo:

Após clicar no botão "Concluir transação", será gerada a transação no DevTools:

{tipoTransacao: 'Depósito', valor: '500', data: '2023-04-12'}

Além de ter objeto representando a transação, o formulário estará limpo.

Atualizando o saldo

Agora precisamos atualizar o saldo conforme o tipo de transação realizada. Para isso, antes do registro da transação (bloco da constante novaTransacao), vamos usar a condicional if para validar o tipo de transação e saber o tipo de operação que será feita no saldo.

Entre os parênteses do bloco if, vamos adicionar tipoTransacao sendo igual (==) a "Depósito". Se for esse o caso, precisamos somar o valor, então teremos saldo += valor.

if (tipoTransacao == "Depósito") {
    saldo += valor;
}

Caso contrário, ou seja, else, se o tipo de transação for "Transferência" ou (||) "Pagamento de Boleto", faremos uma subtração no saldo com o valor de cada transação.

else if (tipoTransacao == "Transferência" || tipoTransacao == "Pagamento de Boleto") {
    saldo -= valor;
}

Se por algum motivo houver outro tipo de transação diferente dos mencionados, teremos um alerta (alert()) indicando que a transação é inválida, pois os requisitos indicam exatamente os tipos de transação que nossa aplicação deve aceitar.

Nesse caso, adicionaremos a palavra-chave return para parar a execução da função.

else {
    alert("Tipo de Transação é inválido!");
    return;
}

Se o saldo for atualizado, pegaremos o elemento que representa o saldo, ou seja, elementoSaldo, seguido de textContent, e atualizaremos com o novo saldo (saldo):

elementoSaldo.textContent = saldo;

Resultado do trecho adicionado ao arquivo bytebank.js:

const inputTipoTransacao = elementoFormulario.querySelector("#tipoTransacao");
const inputValor = elementoFormulario.querySelector("#valor");
const inputData = elementoFormulario.querySelector("#data");

let tipoTransacao = inputTipoTransacao.value;
let valor = inputValor.value;
let data = inputData.value;

if (tipoTransacao == "Depósito") {
    saldo += valor;
} else if (tipoTransacao == "Transferência" || tipoTransacao == "Pagamento de Boleto") {
    saldo -= valor;
} else {
    alert("Tipo de Transação é inválido!");
    return;
}

elementoSaldo.textContent = saldo;

const novaTransacao = {
    tipoTransacao: tipoTransacao,
    valor: valor,
    data: data
}

console.log(novaTransacao);
elementoFormulario.reset();

Vamos fazer um teste rápido no navegador para conferir se nossa aplicação funciona corretamente. Preencheremos o formulário com os seguintes dados, por exemplo:

Após enviar o formulário, teremos o registro da transação no DevTools e será debitado o valor da transferência no saldo. Agora vamos testar o tipo de transação "Pagamento de Boleto":

Também teremos o registro no DevTools e o valor atualizado do saldo da conta.

Conclusão

De forma geral, nossa aplicação está funcionando. Mas quais são os problemas com os quais ainda podemos nos deparar?

No nosso código, o VS Code não está indicando nenhum erro, e quando testamos no navegador, a aplicação funciona normalmente. Porém, vamos analisar o que acontece ao fazermos uma transação do tipo "Depósito":

Com esses valores, em vez de somar o valor ao saldo, o valor é concatenado, ou seja, temos os 2200 que já estavam no saldo da conta, seguido de 300 correspondente ao valor do depósito.

Isso acontece porque todos os dados que vêm de elementos de formulário são do tipo string, ou seja, textos. Assim, sempre que tentamos fazer uma operação de adição com um texto, mesmo que o valor de saldo seja um número, o JavaScript prioriza o texto. Então, ele converte o valor do saldo em texto e une ao valor da transação, em vez de fazer a operação de soma.

Sobre o curso TypeScript na prática: implemente um projeto completo com TypeScript e módulos

O curso TypeScript na prática: implemente um projeto completo com TypeScript e módulos possui 214 minutos de vídeos, em um total de 51 atividades. Gostou? Conheça nossos outros cursos de JavaScript em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda JavaScript acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas