📚 Guia de Tipos para TypeScript
Published: 2020-07-01 21:23:24

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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:

```javascript
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:

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

---

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

---  

## ⚡️ Tipagem

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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.

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

#### String:

Conjunto de caracteres envoltos de aspas simples ou duplas ou crases ([Template String](https://medium.com/collabcode/template-string-%C3%A9-top-demais-02-5d8964726a32#:~:text=Portanto%2C%20para%20usar%20o%20Template,JavaScript%20fica%20dentro%20das%20chaves%7D%20.)). Estas representam letras, palavras ou frases.

```typescript
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**.

```typescript
const myNumber: number = 8;
```

#### Boolean:

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

```typescript
const myBoolean: boolean = true;
```

#### Array:

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

```typescript
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.

```typescript
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.

```typescript
enum MyNumbersList {Zero, One, Two}

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

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

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

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

Além disso, podemos fazer o processo inverso.

```typescript
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.

```typescript
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.

```typescript
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:

```typescript
// 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.

```typescript
// 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

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

```typescript
// 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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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)

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

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

#### Sintaxe "as" (as syntax)

```typescript
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.

```typescript
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:

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

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

## 🖥 Interface

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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:

```typescript
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.

```typescript
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: 

```typescript
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:

```typescript
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:

```typescript
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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **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.

```typescript
// 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.
```

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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:

```typescript
// 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

<br />

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

<br />

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

<br />

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

<br />

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