Tipos e Dados

Tipos e Dados

Jornada Javascript: Tipos e Dados

O conteúdo dessa lição se baseia na base dos tipos e dados que aprendemos na 3° lição da jornada Javascript. Link abaixo!

Para acessar o link da lição, clique aqui.

Assim como no Javascript, no Typescript nós também possuímos os mesmos tipos de dados, a diferença é que aqui eles são declarados de forma um pouco mais explicita.

Explicita no sentido de dizermos ao programa que tipo de dado aquela variável ou função vai trabalhar. E depois de definido o seu tipo, aquela variável ou função não poderá receber dados de outros tipos (ao menos que o tipo esteja declarado como any).

Type Annotation e Type Inference

No universo do Typescript, nós podemos declarar nossos tipos de dados de duas formas diferentes:

  • Type Annotation,
  • Type Inference.

Type Annotation

Também conhecido como tipo de anotação, é quando definimos nossos tipos de dados de forma EXPLICITA!

E isso é feito adicionando o : tipo após a declaração do nome de uma variável ou parâmetro de uma função:

let nomeDaVariavel: tipo = ...

Durante a nossa jornada iremos utilizar este tipo de anotação.

Type Inference

Também conhecido como tipo de inferência, é um recurso do próprio Typescript em que ele deduz de forma automática o tipo de uma variável ou expressão com base no valor inicial que foi atribuído a ela.

Ou seja, aqui o tipo de dado é declarado de forma IMPLÍCITA!

Que nada mais é do que fazer aquilo que já estamos acostumados com o Javascript, por exemplo:

let nome = "Micilini"//Deduz que é uma string
let idade = 28;//Deduz que é um number

Quando usar Type Annotation ou Type Inference?

Type Annotation: É útil quando você deseja especificar explicitamente o tipo de uma variável ou função, o que pode ajudar na clareza do código e na detecção de erros de tipo durante o desenvolvimento.

Type Inference: É conveniente e reduz a quantidade de código redundante, pois o TypeScript deduz automaticamente os tipos com base nos valores atribuídos. Isso pode tornar o código mais limpo e menos propenso a erros de digitação.

Sendo assim:

Use anotações de tipo quando quiser garantir explicitamente o tipo de uma variável ou função, especialmente em casos onde o tipo não é óbvio.

Tal prática que vamos adotar nesta jornada 😉

Tipos Primitivos em Typescript

No Typescript nós temos ao todo 7 diferentes tipos de dados primitivos, são eles:

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • BigInt
  • Symbol

Veremos o funcionamento de cada um deles abaixo 😉

Number

No typescript nós temos o tipo number, que representa um valor numérico, que podem incluir tanto inteiros quanto números de ponto flutuante (decimais), podendo ser positivos ou negativos.

Veremos abaixo algumas caraterísticas do tipo number 🙂

Inteiros: o JavaScript moderno trata números como números de ponto flutuante de 64 bits, então o intervalo de inteiros é de aproximadamente de -9 quadrilhões a 9 quadrilhões.

Ponto Flutuante: além de números inteiros, podemos usar números fracionários (decimais) com precisão limitada.

Vejamos alguns exemplos no uso do number em Typescript:

let idade: number = 30;
var preco: number = 99.99;
const temperatura: number = -10.5;
let pi: number = 3.14159;
let maiorNumero: number = Infinity;
let naoEhNumero: number = NaN;

Observe que declaramos essas variáveis usando o let, var e const, assim como estamos acostumados a fazer no Typescript.

Observação: O Typescript possibilita também a inserção de métodos númericos.

String

No typescript, nós temos também o tipo string, que representa uma string (um texto), que pode incluir diversos caracteres como letras, números além de caracteres especiais.

Vejamos alguns exemplos no uso da string em Typescript:

let nome: string = "Maria";
const mensagem: string = 'Olá, mundo!';

var cumprimento: string = "Olá, " + nome + "!";//Exemplo de concatenação

Veja que estamos usando o termo string logo após declararmos o nome da nossa variável.

Assim como fazemos no Javascript, o Typescript também aceita interpolação:

let idade: number = 30;
let mensagemIdade: string = `Você tem ${idade} anos.`;

Observação: O Typescript possibilita também a inserção de métodos de texto.  

Boolean

No typescript, nós temos também o tipo boolean, que representa um valor booleano (true ou false). Vejamos alguns exemplos do seu uso:

let ativo: boolean = true;
let maiorIdade: boolean = false;

let temContaBancaria: boolean = true;
let temCartaoCredito: boolean = false;

let elegivelParaEmprestimo: boolean = temContaBancaria && !temCartaoCredito;

let possuiPermissao: boolean = true;

Nos códigos acima estamos declarando um tipo boolean, junto com exemplos de operadores lógicos, que por sua vez, permanecem os mesmos do Javascript.

Null e Undefined

Em TypeScript, assim como em JavaScript, null e undefined são dois valores distintos que são usados para representar a ausência de valor ou valores que não foram definidos.

Para verificar se uma variável é undefined, você pode compará-la diretamente com undefined:

let nome: string = "";

if (nome === undefined) {
 console.log("O nome não foi definido.");
}

let carro: string | null = null;

let endereco: string | null = null;

if (endereco === null) {
 console.log("O endereço não está disponível.");
}

Lembrando que não é possível definir tipos de variáveis como null ou undefined, como por exemplo:

let nulo: null = null;//Vai dar erro!
const naoDefinido: undefined = undefined;//Também vai dar erro

O que podemos fazer é: Definir um tipo e atribuí-lo como null ou undefined (enquanto aquela variável ainda não recebe nenhum valor):

let nome: string = null; // Erro se "strictNullChecks" estiver ativado
let idade: number = undefined; // Erro se "strictNullChecks" estiver ativado

No caso dos dois comandos acima, o primeiro recebe uma string e o segundo um number, e apesar de ambos estarem com valores nulos, eles só podem conter uma string (nome) ou um número (idade).

O que é o strictNullChecks e como ativar/desativar?

No typescript, existe uma configuração na qual deixamos o compilador mais rigoroso com relação aos valores null e undefined.

Ele é uma parte das opções de configuração de "strict mode" do TypeScript, que são destinadas a melhorar a segurança e robustez do código, especialmente em relação ao tratamento de tipos.

Quando ativado, você não pode atribuir null ou undefined a uma variável que foi tipada explicitamente para não aceitar esses valores.

Como estamos usando o terminal (prompt de comando) para compilar códigos TS em JS, você pode ativar essa checagem passando a flag --strictNullChecks da seguinte forma:

tsc --strictNullChecks arquivo.ts

Para manter desativado é só não passar essa tag, ok?

Agora, se você estiver usando Typescript com ReactJS ou NodeJS, basta que você ative essa opção criando uma nova chave dentro do arquivo tsconfig.json, que geralmente fica localizado na pasta raiz da sua aplicação:

{
 "compilerOptions": {
 "strictNullChecks": true
 }
}

BigInt

No typescript, também temos o bigint que é números inteiros gigantescos, como por exemplo: 1234567890123456789012345678901234567890n.

Importante: inicialmente o Bigint pode estar desativado, isto é, quando o compilador do Typescript está setado para versões menores que ES2020, o que ocasionaria o seguinte erro: "BigInt literals are not available when targeting lower than ES2020".

Para resolver este erro, crie uma nova chave dentro do arquivo tsconfig.json da seguinte forma:

{
 "compilerOptions": {
 "lib": [
 "es2020"
 ],
 "module": "commonjs",
 "target": "es2020",
}

Para resolver isso via terminal, basta passar uma flag chamada de --target da seguinte forma:

tsc --target ES2020 arquivo.ts

Agora vejamos como declarar este tipo de dado:

let numeroGrande: bigint = 1234567890123456789012345678901234567890n;

let a: bigint = 123n;
let b: bigint = 456n;

let soma: bigint = a + b; // 579n
let diferenca: bigint = b - a; // 333n
let produto: bigint = a * b; // 56088n
let quociente: bigint = b / a; // 3n (divisão de inteiros)
let resto: bigint = b % a; // 87n

No comando acima, vimos que também é possível realizar operações matemáticas com Typescript, e que elas não se diferem daquilo que vimos no JS.

Observação: O Typescript possibilita também a inserção de métodos de númericos para este tipo em específico. 

let numero: number = 123;
let numeroGrande: bigint = BigInt(numero); // converte number para bigint
let numeroNovo: number = Number(numeroGrande); // converte bigint para number

Symbol

Por fim, nós temos o tipo symbol é usado para criar valores únicos e imutáveis que são frequentemente usados como identificadores únicos em propriedades de objetos.

Vejamos como ele funciona:

let sym1 = Symbol();
let sym2 = Symbol("descricao");

Para usá-lo dentro de um objeto, basta fazer isso da seguinte forma:

const chave1 = Symbol("chave1");
const chave2 = Symbol("chave2");

let objeto = {
 [chave1]: "valor1",
 [chave2]: "valor2"
};

console.log(objeto[chave1]); // "valor1"

Fatos interessantes sobre o Typescript

Como você já sabe, o typescript precisa ser transformado para Javascript para ser executado tanto no front-end quanto no back-end.

Se você pegar todos os arquivos que criamos nesta lição, verá que na versão .js de cada um deles, a tipagem estática que definomos em nossas variáveis, simplesmente some 😅

Esse é um comportamento normal, pois o JS não tem esse suporte de tipagem.

Dessa forma, conseguimos compreender que o Typescript é só uma ferramenta de apoio a criação de códigos mais "certos". Pois no final tudo será convertido para o nosso bom e velho Javascript.

Podemos dizer então que programar em TS é como um pair programming, mas o que é isso?

Pair programming é uma prática de desenvolvimento de software onde dois programadores trabalham juntos em um mesmo computador. Nesta abordagem, um dos programadores, chamado de "driver" (motorista), está encarregado de escrever o código, enquanto o outro, chamado de "navigator" (navegador), revisa cada linha de código à medida que é escrita.

No caso, o motorista somos nós, e o navegador é o compilador do TS 😊

Lembrando que após a compilação de código Typescript em Javascript, o Typescript não tem mais nenhum efeito, logo, ele não pode mais nos ajudar no desenvolvimento.

Gerando erros de tipagem estática com Typescript

Como vimos acima, nós aprendemos a declarar nossos tipos primitivos usando Typescript.

E para confirmar que o compilador gera erros quando tentamos atribuir outros tipos, nós vamos fazer o seguinte teste:

let nome: string = "Micilini Roll";
nome = 15.98;//Essa linha vai gerar um erro

console.log(nome);

Quando executamos um tsc index.ts, o compilador vai gerar este erro:

Apesar de um arquivo index.js ser gerado, vemos que o TS apontou um erro no momento em que tentamos atribuir um tipo number para um tipo string.

Em aplicações reais feitas com ReactJS ou NodeJS, um código como esse nunca seria compilado, ocasionando um erro na aplicação inteira.

Arquivos da lição

Os arquivos desta lição podem ser encontrados no repositório do GitHub por meio deste link.

Conclusão

Nesta lição você aprendeu a declarar os tipos primitivos no Typescript.

Até a próxima 🙃