📚 Guia de Tipos para TypeScript

rafalopesmelo

Rafael Lopes de Melo

Posted on July 1, 2020

📚 Guia de Tipos para TypeScript

         Uma das linguagens mais interessantes para o desenvolvimento de aplicativos em larga escala é o TypeScript. Ele é único pois se trata de um "superset" ("superconjunto") JavaScript, mas com tipos, interfaces e diversas outras adições; isto quer dizer que não tem a intenção de substituir o JavaScript, apenas pretende facilitar o desenvolvimento e tornar aplicações JS mais escaláveis e manuteníveis.

         Esta linguagem não requer conhecimentos extremamente avançados em JavaScript ou em uma linguagem fortemente tipada (Java ou C), sendo assim, um desenvolvedor intermediário em JS já pode usufruir de suas vantagens, visto que é possível aprender suas funcionalidades aos poucos e aplicá-las gradativamente.


Este guia busca abordar conceitos ligados à teoria da linguagem, deixando de lado certas partes como instalação e configuração.


💙 Pequenas implementações da linguagem

         Antes de entrarmos a fundo nos tipos do TypeScript, é interessante observar suas pequenas implementações e como elas funcionam dentro da linguagem.

         Existem 2 melhorias principais em funções: parâmetros opcionais e valores padrão.

Parâmetros opcionais

São facilmente identificados pelo "?" após sua declaração:

function myFunction(arg1, arg2, optionalArg?) {
 //...
}

Parâmetros com valor padrão

Para criar um valor padrão para um parâmetro, basta defini-lo junto com sua declaração na função:

function myFunction(arg1, arg2, withDefaultValueArg = 30) {
 //...
}

Ao definir um valor padrão a um argumento, ele automaticamente se torna opcional.


⚡️ Tipagem

         Ao contrário do que muitos pensam, o TypeScript não é uma linguagem fortemente tipada, visto que não é necessário tipar todas as variáveis. Os tipos de variáveis simples conseguem ser inferidos automaticamente pelo TS ao serem declaradas, como um number ou string. A esta funcionalidade damos o nome de Inferência de Tipos.


Qualquer variável cujo tipo não pode ser inferido pelo TS, recebe o tipo "any" automaticamente.


Tipos:

Any:

Exatamente qualquer coisa, usado quando não se sabe ao certo o tipo da variável, a principal situação é quando não sabemos os tipos das entidades de uma biblioteca terceira. Seu uso deve ser evitado ao máximo.

let anyType: any;
anyType = 5;
anyType = 'Hello World';
anyType = true;

String:

Conjunto de caracteres envoltos de aspas simples ou duplas ou crases (Template String). Estas representam letras, palavras ou frases.

const myString: string = 'My String';

Number:

Qualquer número, seja ele natural, inteiro ou racional. Não possuem aspas, pois assim seriam tratados como string.

const myNumber: number = 8;

Boolean:

Tipo de variável que pode receber apenas dois valores: "true" ou "false".

const myBoolean: boolean = true;

Array:

Um array é uma lista não ordenada de dados, possui diversos elementos de mesmo tipo.

const myNumberArray: Array<number> = [1, 2, 5, 10];

const myStringArray: Array<string> = ['Hello', 'World', '!'];

Tuple:

Apesar de o JS em si não possuir tuplas, o TS permite emulá-las em um array. A tupla é uma lista, geralmente pequena, de elementos finitos com cada elemento possuindo um tipo específico.

const myTuple: [string, number] = ['Hello World', 16];

Uma tupla pode conter itens opcionais utilizando o "?".


Enum:

É uma forma de adicionar nomes familiares a uma lista de números. Por padrão, os valores começam em 0 e são auto incrementais.

enum MyNumbersList {Zero, One, Two}

const myNumber: MyNumberList = MyNumbersList.One; // 1

Podemos também definir um valor específico para cada elemento.

enum AgeList {
  MyAge = 18,
  DadAge = 40,
  MomAge = 38
}

const myAge: AgeList = AgeList.MyAge; // 18

Além disso, podemos fazer o processo inverso.

enum ColorList {Red, Green, Blue}

const myColor: string = ColorList[1]; // 'Green'

Void

É como o oposto de any, void é a ausência completa de tipo. Geralmente é utilizado para tipar um função quando a mesma não retorna nada.

function helloWorld(): void {
  console.log('Hello World!')
}

Atribuir void a uma variável não é útil pois só podemos defini-las como null ou undefined nesses casos.


Caso desejemos guardar o retorno de uma função void em uma variável, teremos o valor undefined.


Null e Undefined

Assim como void, null e undefined não são muito úteis por si só, geralmente são utilizados com Tipos de União (que veremos mais para frente). Null e undefined simbolizam a ausência de valores em uma variável.

const u: undefined = undefined;
const n: null = null;

Never

Este tipo indica que uma função nunca deve retornar, quando temos certeza de que algo nunca vai ocorrer. Alguns casos em que este tipo é utilizado são:

// Função que sempre lança um erro:
function error(): never {
  throw new Error('Something went wrong!')
};

// Função com um fim inalcançável 
function Loop() {
  while(true) {
    console.log('I always do something and never end')
  }
}

Object

Segundo a documentação do TypeScript, um objeto é tudo aquilo que não se encaixa em nenhum tipo primitivo.

// Define as propriedades do objeto
const person: {
  name: string;
  age: number;
  description?: string; // Propriedade opcional
};

// Dá um valor a cada propriedade
person = { 
  name: 'Rafael',
  age: 18
};

👫🏽 Tipos de União

         Também chamados de Union Types, esta funcionalidade é utilizada quando precisamos que uma variável possa conter mais de um tipo.

// Declara uma variável que recebe nome (string) e idade (string ou number)
function sayMyNameAndAge(name: string, age: string | number) {
  console.log(`My name is ${name} and I'm ${age} years old`)
};

sayMyNameAndAge('Rafael', 18); // OK
sayMyNameAndAge('Rafael', '18'); // OK

🔍 Asserção de tipo

         Em inglês, Type Assertions. Algumas vezes haverá situações em que você saberá mais sobre um valor do que o próprio TypeScript sabe. Asserção de tipo é uma forma de dizer ao compilador "confie em mim, eu sei o que estou fazendo", evitando possíveis erros em tempo de compilação (não tem influência em tempo de execução).

Asserções de tipo possuem duas sintaxes possíveis:

Sintaxe Menor que/Maior que (angle-bracket syntax)

const message: any = 'This is a string with any type!';

const messageLength: number = (<string>message).length;

Sintaxe "as" (as syntax)

const message: any = 'This is a string with any type!';

const messageLength: number = (message as string).length;

🗺 Type Alias

Basicamente cria um nome para determinado tipo, são similares às interfaces, mas podem nomear primitivos, uniões, tuplas, etc.

type myTuple = [string, number, boolean];

const tuple: myTuple = ['Hello', 25, true] // OK

Podemos também utilizar esta funcionalidade para definir exatos valores possíveis para uma variável:

type OS = 'Windows' | 'Mac OS' | 'Linux';

const myOS: OS = 'Windows'; // OK
const myPhoneOS: OS = 'ios' // Error

🖥 Interface

         Uma interface é, em essência, os tipos literais de um objeto. Esta funcionalidade permite que utilizemos objetos do mesmo tipo sem repetição de código.

Observe a declaração de dois objetos de mesmas propriedades sem o uso de interfaces:

const point: {
  x: number;
  y: number;
};

point = { x: 5, y: 12 };

const point2: {
  x: number;
  y: number;
};

point2 = { x: 8, y: 20 };

E agora veja o mesmo exemplo, porém, desta vez, utilizando interfaces.

interface IPoint {
  x: number;
  y: number;
};

const point: IPoint = { x: 5, y: 12 };
const point2: IPoint = { x: 8, y: 20 };

Podemos também estender uma interface caso queiramos adicionar certa propriedade a determinado objeto. Veja:

interface IPoint {
  x: number;
  y: number;
};

interface IPoint3d extends IPoint{
  z: number;
};

const point: IPoint = { x: 5, y: 12 };
const point3d: IPoint3d = { x: 8, y: 20, z: 5 };

Ou ainda melhor, podemos definir "z" como uma propriedade opcional e assim criar uma interface única. Observe:

interface IPoint {
  x: number;
  y: number;
  z?: number;
};

const point: IPoint = { x: 5, y: 12 };
const point3d: IPoint = { x: 8, y: 20, z: 5 };

Segundo a documentação, apesar de serem parecidos, as interfaces trazem maiores capacidades dentro do código. Por isto, em uma perspectiva ideal, é preferível utilizar interfaces ao invés de type alias, sendo este utilizado apenas em último caso.


📐 Tipos de Intersecção

Também chamados de Intersection Types, esta funcionalidade faz com que determinada variável tenha que atender aos contratos de todos os tipos assinalados a ela. Veja:

interface IUser {
  name: string;
  password: string;
};

interface IChar {
  nickname: string;
  level: number;
};

type UserInfo = IUser & IChar;

const userInfo: UserInfo = {
  name: 'Rafael',
  password: '123456',
  nickname: 'LopeKillz',
  level: 255
};

💊 Tipos Genéricos

         Tipos genéricos ou Generic Types podem ser entendidos como um tipo que deve incluir ou fazer referência a outro tipo. Os principais e mais comuns são Arrays e Promises.

// Array
const numbersArray: Array<number> = [0 , 5, 10]; // Declara um Array de números

// Promise
async function myAsyncFunction(): Promise<string>; // Declara uma Promise que retorna uma string quando resolvida.

         Com o uso dos tipos genéricos, podemos evitar a utilização do tipo any em uma função que utiliza um parâmetro com diversos tipos possíveis. Com esta estratégia, permitimos que o tipo do parâmetro seja declarado apenas quando a função é chamada. Veja:

// Primeiro declaramos uma função que recebe um parâmetro de qualquer tipo e o retorna
function indentify<T>(arg: T): T {
  return arg;
};

// E então podemos chamar a função acima passando como parâmetro uma string
identify<string>('Hello World!');

// Ou podemos também chamar a mesma função passando um number
identify<number>(18);

Na maioria das vezes não precisamos definir o tipo específico do parâmetro durante a chamada da função graças à inferência de tipos.


✔️ Conclusão:

Este foi um guia geral sobre os tipos do TypeScript e como utilizá-los da melhor forma. Evidente que esta linguagem possui diversas outras funcionalidades, como decoradores e símbolos, mas é importante começar pelo básico e se aprofundar aos poucos.

Este artigo é uma ótima porta de entrada para o mundo do JavaScript tipado, visto que passamos por muitas funcionalidades de forma simples e descomplicada. Espero ter ajudado quem dedicou seu tempo a ler todos os tópicos, e qualquer dúvida estou à disposição!

Caso queira se aprofundar mais neste assunto, recomendo visitar todas as referências que deixei logo abaixo, principalmente a documentação oficial!

📜 Referências:

Documentação oficial do TypeScript: https://www.typescriptlang.org/docs/home.html

Artigo de Eduardo Rabelo, "TypeScript: O guia definitivo": https://medium.com/@oieduardorabelo/typescript-o-guia-definitivo-1a63b04259cc

Mini curso de Willian Justen no YouTube: https://www.youtube.com/playlist?list=PLlAbYrWSYTiPanrzauGa7vMuve7_vnXG_

Tutorial de TypeScript em TutorialsTeacher: https://www.tutorialsteacher.com/typescript

Artigo "Tipos Básicos - Manual do TypeScript", de WebDevBr: https://webdevbr.com.br/tipos-basicos-manual-do-typescript

💖 💪 🙅 🚩
rafalopesmelo
Rafael Lopes de Melo

Posted on July 1, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related