Principais diferenças entre types e interfaces em TypeScript
Tags: typescript, javascript, webdev, beginners
Published: 2022-01-13 00:27:27

TypeScript é um superset de JavaScript que têm sido cada vez mais usado pela comunidade, muitas novas funcionalidades e o decorrer dos updates da ferramenta a diferença entre types e interfaces vêm diminuindo gradativamente, porém ainda existem cenários ideais para se utilizar um ou outro.

Neste post vou tentar esclarecer um pouco o assunto e te ajudar a decidir entre **tipos e interfaces** em seus projetos.

## Principais Funcionalidades
Bora dar uma olhada nas principais características e funcionalidades dos **tipos** e das **interfaces** e compararmos sua utilização.

### Interfaces
Ideais para definir a **estrutura** de um objeto ou classes, as interfaces são ótimas para desenvolver um projeto aberto para **implementações** e **extensões** de comportamento.

```ts
interface VerifyToken {
  (token: string): boolean;
}

interface AuthContext {
  authToken: string;
  verifyToken: VerifyToken;
}

const authContext: AuthContext = {
  authToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
  verifyToken: (token) => token.length === 36,
}
```

- **Podem ser implementadas por classes**:
Interfaces podem definir estruturas genéricas que podem ser reutilizadas na construção de classes e objetos.
```ts
interface Person {
  name: string;
};

class User implements Person {
  name = 'John Doe';
};

const user: Person = {
  name: 'John Doe',
};
```

- **São extensíveis**: Você pode extender interfaces na declaração de outras interfaces.
```ts
interface Person {
  name: string;
};

interface User extends Person {
  address: string; 
};

const user: User = {
  name: 'John Doe',
  address: 'Brazil',
};
```

- **Permitem** ***declaration merging***: Declaration merging é uma forma de extender uma interface, porém de forma menos explícita.
```ts
interface Person {
  name: string;
};

interface Person {
  age: number;
};

const person: Person = {
  name: 'John Doe',
  age: 20,
};
```

### Types
Apesar de não poderem ser utilizados em definições de classes, os ***types*** são ferramentas poderosas que permitem funcionalidades e combinações avançadas de estruturas, além de adicionar segurança na tipagem de primitivos, funções e objetos.
```ts
type Token = string;
type VerifyToken = (token: Token) => boolean;

type AuthContext = {
  authToken: Token;
  verifyToken: VerifyToken;
}

const authContext: AuthContext = {
  authToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
  verifyToken: (token) => token.length === 36,
}
```

- **Permitem _intersections_ e _unions_:** Pode-se considerar uma das maiores funcionalidades dos type aliases, as intersections e unions permitem combiná-los de várias formas.
```ts
type Person = {
  name: string;
}

type Young = {
  hungry: boolean;
};

type User = Person & { address: string };
type Me = Person & Young;

const user: User = {
  name: 'John Doe',
  address: 'Brazil',
};

const me: Me = {
  name: 'Vinicius',
  hungry: true,
};
```
```ts
type Car = {
  wheels: 4
}

type Motorcycle = {
  wheels: 2
}

let vehicle: Car | Motorcycle = {
  wheels: 4,
} // Car

vehicle = {
  wheels: 2,
} // Motorcycle

vehicle = {
  wheels: 1,
} // Error
```

## Afinal, como decidir?
A documentação do TypeScript deixa explícito que escolher entre type aliases e interfaces é algo muito relacionado ao gosto pessoal e necessidades do projeto, porém sugere utilizar ***interfaces*** até que você precise de alguma funcionalidade específica dos ***types***.

É importante citar também, que para como bibliotecas e frameworks, é altamente sugerido utilizar ***interfaces*** para que sua API seja aberta para implementações e extensões de comportamento.

Fica claro que as maiores diferenças são em relação à forma de se declarar as estruturas, como por exemplo em funções, onde os ***types*** se mostram muito mais limpos e diretos ao ponto.
```ts
// Com Interfaces
interface HelloFunction {
  (name: string): string;
}
const hello: HelloFunction = (name) => name;

// Com Types
type HelloFunction = (name: string) => string;
const hello: HelloFunction = (name) => name; 
```

A combinação de ***types*** e ***interfaces*** na medida certa traz grandes benefícios, apesar de cada um ter seu caso de uso ideal, quando utilizados em conjunto eles podem abrir possibilidade para a utilização de [features mais avançadas da linguagem](https://www.typescriptlang.org/docs/handbook/advanced-types.html).

- ***interfaces***: definir estruturas de objetos e classes.
- ***types***: definir funções, utilizar funcionalidades mais avançadas como `conditional types`, `type guards`, etc.

```ts
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

interface Animal {
  live(): void;
}
interface Dog extends Animal {
  woof(): void;
}

type Example1 = Dog extends Animal ? number : string;
//   ^ = type Example1 = number

type Example2 = RegExp extends Animal ? number : string;
//   ^ = type Example2 = string
```

Espero que eu tenha conseguido esclarecer um pouco as coisas pra você, todos os exemplos que escrevi foram baseados na documentação oficial do TypeScript, a qual recomendo a leitura.

https://www.typescriptlang.org/docs/handbook/