Fundamentos de Angular e TypeScript

Fundamentos de Angular e TypeScript

Olá, Dev! Quando estamos conhecendo o mundo do front-end, nos deparamos com alguns caminhos diferentes que podemos seguir, como por exemplo o do React, Vue ou Angular.

No entanto, quando optamos pelo Angular, encontramos um passo diferenciado: o TypeScript.

E se você gostaria de entender melhor porque e como o Angular utiliza essa tecnologia, está no lugar certo.

Vamos abordar os principais motivos pelos quais o Angular trabalha com TypeScript e alguns conceitos-chave que você precisa compreender para aproveitar o melhor desse framework aliado aos recursos do TypeScript. Vamos lá?

Por que usamos TypeScript com Angular?

Em 2009, surgiu o Angular, através da Google, em sua primeira versão. Ele era desenvolvido em JavaScript e apesar de sua grande utilização, apresentava muitos problemas que precisavam ser solucionados.

Em 2016, a maneira que o time da Google encontrou de resolver isso foi reescrevendo o framework, e dessa vez, para a surpresa de todos(as), com TypeScript.

Alguns pontos tornaram essa escolha a mais apropriada: o primeiro é a variedade de funcionalidades que o TypeScript traz como, por exemplo, o intellisense dos editores de texto e a detecção de falhas em tempo de desenvolvimento e compilação, que contribuem para que o Angular tenha toda a estabilidade que conhecemos hoje.

Além disso, a maneira como os códigos são organizados no TypeScript se assemelha um pouco com o padrão orientado a objetos de algumas linguagens back-end, o que também favorece que o aprendizado de Angular por pessoas que têm experiência com desenvolvimento back-end seja facilitado.

Banner promocional da Semana Carreira Tech, organizada pela Alura e FIAP. Texto: 'Descubra como graduações tech estão transformando o futuro. Cinco lives gratuitas para você mergulhar nas áreas mais transformadoras da atualidade, desde o que se estuda nas graduações até a prática do mercado. Garanta sua vaga de 01 a 05 de julho.' Imagem de profissionais usando equipamentos tecnológicos avançados, como óculos de realidade aumentada. Botão destacado com a chamada 'Garanta sua vaga'. Logotipos da Alura e FIAP no canto superior direito.

O TypeScript

Você pode estar se perguntando: “mas Rafaela, o que é um superset?”. A resposta é simples: ser um superset ou superconjunto significa que o TypeScript faz tudo que o JavaScript faz, além de algumas coisas extras.

Se pensarmos numa analogia, é como se o JavaScript que já conhecemos ganhasse superpoderes.

A seguir, vamos conhecer alguns desses superpoderes e tudo o que você precisa saber para aproveitá-los em seus projetos se você quiser ir do JavaScript ao TypeScript!

Tipagem estática

Quando alguém pergunta o que é TypeScript, existe uma máxima que costumamos ouvir muito no mundo do desenvolvimento: TypeScript é JavaScript fortemente tipado! Essa afirmação não está totalmente errada.

Apesar do TypeScript trazer muitas outras funções interessantes que o JavaScript não inclui, a tipagem estática é um de seus superpoderes que mais se destaca.

Observe o exemplo a seguir para entender melhor o que é essa tipagem e como pode nos ajudar bastante durante o desenvolvimento.

Suponha que você precise criar um código que receba nome e idade de uma pessoa e calcule o ano de nascimento dela:

let nome = "Maria";
let idade = 19;

Ao criar as variáveis acima, definimos que o nome recebeu a string “Maria” e a idade recebeu o número 19.

Assim, o JavaScript presume o tipo de cada variável dinamicamente, a partir do valor que atribuímos a elas. Por isso, dizemos que o JavaScript possui uma tipagem dinâmica.

No entanto, nessas condições de tipagem que o JavaScript nos proporciona, a pessoa desenvolvedora recebe muita liberdade para alterar essas variáveis de modo que qualquer uma delas pode receber um valor de qualquer tipo.

Por exemplo, se atribuirmos novamente o valor da variável idade com um valor do tipo string, como você pode observar abaixo, não recebemos nenhum tipo de alerta ou erro:

idade = "Dezenove";

Pensando no código para calcular o ano de nascimento de uma pessoa que usamos de exemplo anteriormente, se o caso acima acontecesse, o cálculo já seria afetado e não seria possível chegar a um resultado.

Isso pode parecer um problema pequeno, até que imaginamos o impacto em uma aplicação grande na qual existem várias pessoas desenvolvedoras trabalhando.

Se existir o uso de uma variável como a de idade que criamos acima que seja importante para as funções desse código e acidentalmente uma pessoa desenvolvedora muda seu valor para um tipo diferente como mostramos acima, isso pode ter consequências no bom funcionamento do sistema.

E como o JavaScript não nos alerta sobre esse erro, ele poderia passar despercebido por muito tempo.

Para resolver isso, existe a tipagem estática do TypeScript, que significa que ao criar uma variável temos que pré-definir seu tipo e caso esse tipo seja desrespeitado em algum momento, deve surgir um alerta em tempo de compilação para que as pessoas desenvolvedoras consigam identificá-lo.

Para isso, renomeei o arquivo adicionando a extensão .ts, ao invés de .js e automaticamente o erro foi evidenciado:

Tela do editor de código Visual Studio Code, com o arquivo script.ts aberto, com quatro linhas. Na primeira há o seguinte código: let nome = "Maria"; Na segunda linha, let idade = 19; A terceira linha está vazia e a quarta linha tem o código: idade = "Dezenove"; Neste código, a variável idade está sublinhada em vermelho indicando que há um erro na atribuição de valor dessa variável.

Também conseguimos ver detalhadamente a descrição do erro:

Tela do editor de código Visual Studio Code, com o arquivo script.ts aberto, destacando a descrição do erro na atribuição de valor da variável idade = "Dezenove"; na qual o seguinte erro é exibido pelo intellisense: Type ‘string’ is not assignable to type ‘number’. ts(2322).

Isso vai facilitar o processo de desenvolvimento e a identificação das falhas antes mesmo do programa ser executado, que nesse caso fica evidente que foi um equívoco nos tipos.

Para corrigir no TypeScript, fazemos a definição correta dos tipos para evitar falhas futuras e apagamos a reatribuição incorreta. Observe no exemplo abaixo:

let nome: string = "Maria";
let idade: number = 26;

Se você quiser se aprofundar ainda mais trabalhando com tipagem no TypeScript, indicamos a leitura do artigo Typescript: aprimore aplicações com tipagem estática, em que o instrutor Neilton Seguins migra um projeto de JavaScript para TypeScript!

Bom, já entendemos que a tipagem estática é o “carro chefe” dos superpoderes do TypeScript.

Porém, como eu já te disse antes, apesar de importante, a tipagem estática não é o único poder desse superset. Vamos explorar os outros?

Orientação a objetos

Quando trabalhamos com TypeScript é muito importante ter conhecimentos de Programação Orientada a Objetos (POO).

Apesar do uso desse paradigma no TS não ser obrigatório, é assim que ele costuma ser utilizado na maioria das vezes.

O JavaScript também possui suporte à Programação Orientada a Objetos. No entanto, o TypeScript nos traz uma caixa de ferramentas muito mais completa com relação à POO que tornam essa uma opção mais robusta e a experiência de desenvolvimento, melhor.

Sendo assim, se você quer embarcar no TS e não conhece a Programação Orientada a Objetos, é crucial aprender seus conceitos e começar a trabalhar com esse paradigma.

E que tal começar justamente com o conceito de paradigma de programação?

Paradigmas de programação

Um paradigma de programação é a maneira como você organiza a estrutura do seu código para solucionar problemas.

No aprendizado de programação, é muito comum seguirmos no paradigma procedural, que se resume em seguir uma sequência de procedimentos para cumprir o papel daquele código, como se fosse uma lista de passos.

Já o paradigma de Programação Orientada a Objetos organiza o código com base no conceito de objetos.

Classes e Objetos

Para entender o que é um objeto, imagine que precisamos registrar um perfil de usuário e cada usuário possuirá as informações de nome e idade, que chamamos de atributos, além das ações que poderá realizar, que chamamos de métodos.

Com esses atributos e métodos do mundo real, fazemos uma abstração para o código e transformamos isso no que chamamos de classe, que você pode observar a seguir:

class Usuario {
     nome: string;
     idade: number;

    constructor(nome: string, idade: number) {
        this.nome = nome;
        this.idade = idade;
    }
}

Acima criamos a classe usuário. Observe que também criamos um constructor para essa classe. O método construtor é responsável por fazer a configuração inicial quando nosso objeto é instanciado.

Ou seja, graças a ele, quando criamos um novo usuário, podemos passar seu nome e idade como parâmetros e garantir que os valores desses atributos sejam recebidos.

Essa classe é um modelo que servirá como base para criarmos diversos usuários, como você pode observar a seguir:

const usuario1 = new Usuario("Maria", 26);
const usuario2 = new Usuario("Alice", 30);
const usuario3 = new Usuario("Bruno", 28);

Cada usuário criado é um objeto! Assim, chamamos de Programação Orientada a Objetos, pois criamos classes e as instanciamos, ou seja, criamos objetos a partir delas quando lhes atribuímos valores.

Interfaces

Outra ferramenta extremamente útil são as interfaces, que servem para estabelecer contratos ao longo da aplicação.

Para compreendermos melhor, vamos continuar pensando no nosso contexto de classe Usuario.

Assim, precisamos garantir que toda vez que nossa classe seja inicializada, ela realize uma ação, que aqui será exibir uma mensagem de inicialização no console.

Para isso, podemos aproveitar uma interface do Angular chamada OnInit, que ao ser implementada na classe, define que ela precisa trazer obrigatoriamente o método ngOnInit, que será executado toda vez que o componente for inicializado:

import { Component, OnInit } from '@angular/core';

 // propriedades adicionais omitidas

export class Usuario implements OnInit {

  // atributos da classe omitidos

  ngOnInit() {
      console.log('Inicializando usuário...');
  }
}

Acima, implementamos a interfaceOnInit na classe e determinamos que quando houver inicialização, a mensagem “Inicializando usuário…” seja exibida no console.

As interfaces cumprem esse papel de estabelecimento de contratos, como ocorreu acima em que a classe deve implementar o ngOnInit, mas também podemos reproduzir esse comportamento obrigando a classe a trazer atributos pré-determinados, por exemplo.

Além disso, para conseguir aproveitar ao máximo as qualidades do seu TypeScript com orientação a objeto, é muito importante aprender sobre os conceitos de encapsulamento, sobrecarga de funções, herança e polimorfismo em suas aplicações.

Caso você queira se aprofundar no tema de POO, indicamos o artigo POO: o que é programação orientada a objetos?

Injeção de dependências

Seguindo nosso exemplo de perfil de usuário, imagine que você precisasse de um método de login dentro da classe de usuário.

Esse método buscará as informações de login do usuário externamente, em um serviço que vamos chamar de ServicoLogin. Ou seja, nossa classe vai depender do ServicoLogin.

Para que esse serviço cumpra seu papel, vamos precisar injetar essa dependência na classe, como você pode observar a seguir:

class Usuario implements Usuario {
  constructor(
public nome: string, 
public idade: number, 
private servicoLogin: ServicoLogin
) {}

  fazerLogin(): void {
    this.servicoLogin.fazerLogin();
  }
}

Lembra do constructor que usamos anteriormente? Pois então, através dele injetamos o nosso ServicoLogin para ser utilizado dentro da classe Usuario. Assim, ele pode ser aplicado no método de login sem problemas!

Dessa maneira, entendemos que a injeção de dependências (ID) é um padrão de projetos que podemos aplicar com TypeScript e que é muito utilizado quando trabalhamos com Angular para que uma classe possa solicitar dependências de fontes externas ao invés de criá-las.

Para você explorar a ID com mais detalhes, recomendamos o artigo Services e injeção de dependência no Angular, em que a instrutora Nayanne Batista vai te guiar passo a passo no entendimento desse conceito.

Decorators

Ao trabalhar com TypeScript no Angular, você pode encontrar situações em que deseja adicionar funcionalidades extras a classes ou métodos.

Quando trabalhamos com Angular, temos alguns decorators padrão que iremos utilizar, como é o caso do @Component. Observe o exemplo a seguir:

import { Component } from '@angular/core';

@Component({
  selector: 'app-usuario',
  standalone: true,
  imports: [],
  templateUrl: './usuario.component.html',
  styleUrl: './usuario.component.css'
})
export class UsuarioComponent {
//lógica do componente
}

O decorator acima decora nossa classe Usuario e serve para fornecer metadados para o Angular, indicando como o componente deve ser tratado e exibido. Por exemplo:

  • O metadado selector vai especificar como esse componente Usuario pode ser referenciado no template(HTML) da aplicação;
  • O standalone: true define que esse componente é independente, enquanto o imports: [] serve para importar outros componentes que precisaremos usar dentro de Usuario;
  • O templateUrl e styleUrl servem para determinar o caminho até o arquivo HTML e CSS do componente, respectivamente.

Em palavras simples, um decorator no TypeScript é como uma etiqueta que você coloca em uma classe, método ou propriedade para adicionar funcionalidades extras a eles sem precisar mudar seu código diretamente e serve para dizer o que aquela parte do código deve fazer ou como precisa se comportar.

É interessante conhecer outros decorators padrão do TypeScript no Angular, como é o caso do @Input() e @Output, que servirão para auxiliar na comunicação entre componente pai e componente filho.

Além disso, também é possível utilizar o TypeScript para criar decorators personalizados de acordo com sua necessidade, para funções como tornar um método acessível apenas para usuários autenticados, por exemplo.

Os decorators são uma ferramenta muito útil para conseguirmos personalizar e estender o comportamento do código sem deixar de lado a organização.

Conclusão

O TypeScript no Angular nos oferece um “cinto de ferramentas” completo e para conseguirmos aproveitá-lo ao máximo, é muito importante conhecer as particularidades desse superset.

E se você quer explorar mais a fundo o TypeScript para construir aplicações Angular, que tal mergulhar nesse conhecimento com a formação Angular: crie aplicações web ágeis que temos por aqui?

Espero que este artigo tenha ajudado a entender melhor o uso do TypeScript e que você continue firme e forte na sua jornada de aprendizado. Até a próxima! :)

Rafaela Petelin Silvério
Rafaela Petelin Silvério

Graduanda em Sistemas de Informação e Técnica em Desenvolvimento de Sistemas pela ETEC, atua como Scuba, na área de Front-end. Apaixonada por tecnologia, está sempre buscando aprender coisas novas. Seus hobbies favoritos são ler, programar, estudar novos idiomas e assistir séries de comédia.

Veja outros artigos sobre Front-end