Diferenças entre Types e Interfaces no TypeScript
Introdução
Pelo fato do TypeScript recomendar nas suas próprias documentações o uso de interface
muito programadores ficam com dúvidas de quando devem usar type
e o porque da sua relevância. Algo muito discutido na comunidade TypeScript, pois embora muito parecidos, possuem usos exclusivos e específicos em determinadas situações. Abaixo serão mostrados alguns casos de uso na prática para que possamos entender melhor suas diferenças.
Diferenças
- Mesclagem do mesmo Tipo:
A primeira grande diferença que podemos ver entre type
e interface
é em mesclar de tipos que possuem o mesmo nome. Abaixo podemos observar o tipo Teacher
que é uma interface
e que possui uma propriedade name
.
interface Teacher {
name: string;
}
const teacher: Teacher = {
name: 'Filipe Deschamps',
};
console.log(teacher); // { "name": "Filipe Deschamps" }
Uma interface
nos permite criar interface
's com o mesmo nome. Quando interface
's do mesmo nome são criadas, o TypeScript realiza uma mesclagem dessas interface
's. Seu uso é recomendado quando é necessário adicionar um tipo ou novas propriedades para uma interface
de uma biblioteca externa. Segue o exemplo prático abaixo:
interface Teacher {
name: string;
}
interface Teacher {
age: number;
}
const teacher: Teacher = {
name: 'Filipe Deschamps',
age: 37,
};
console.log(teacher); // { "name": "Filipe Deschamps", "age": 37 }
Atenção: Com type
isso não é possível, o TypeScript não realiza essa mesclagem de tipos definidos com type
, pois cada type
deve ser único para que assim possa ser identificado.
- Mapeamento de Tipos:
O type
possui sintaxes reservadas para mapeamento de tipos no TypeScript (in keyof
, typeof
, entre outros...), caso você tente realizar o mesmo usando interface
, um erro será lançado para você, pois não é uma sintaxe válida para uma interface
. Sendo exclusivo para o type
lidar com mapeamentos de tipos. Segue o exemplo prático abaixo:
interface DataNumber {
data: number;
}
// Transforma cada propriedade "P" dentro do tipo "T" para ser uma string
type Stringfy<T> = {
[P in keyof T]: string;
}
const numberToString: Stringfy<DataNumber> = {
data: '42',
}
console.log(numberToString); // { data: "42" }
Atenção: Perceba que a propriedade data
dentro do objeto numberToString
agora é uma string
e não um number
. Isso tudo é possível graças a versatilidade que o type
nos disponibiliza ao lidar com tipos, algo que não é possível com interface
.
- Utilizando
type
como Tipo Primitivo:
O uso de interface
com o intuito de tipar parâmetros em funções, as quais não são robustas o bastante, ou seja, não recebem tantos parâmetros, não é uma boa prática. Uma interface
sempre terá o formato de um objeto, não sendo possível adicionar tipos primitivos ela. Com type
podemos criar tanto tipos com formato de objeto, quanto criar tipos primitivos para funções que recebem somente um argumento. Segue o exemplo abaixo:
type Alias = string; // Um apelido
// Isso aqui
const logger = (alias: Alias) => alias;
// É a mesma coisa que isso!
// const logger = (alias: string) => alias;
console.log(logger('Deschamps')); // "Deschamps"
Atenção: Como dito anteriormente, caso você tente atribuir um tipo primitivo ao uma interface
, um erro de sintaxe do TypeScript será lançado para você. Pois, isso é algo exclusivo do type
.
Conclusão
Com isso, podemos concluir que o type
apresenta uma versatilidade muito maior que a interface
para lidar e manipular com o tipos genéticos e primitivos. Entretanto, existe uma importância da interface
, sendo utilizada para mesclagem com tipos externos de bibliotecas de terceiros e criação de tipos. Portanto, sempre procure criar tipos com type
quando existe a necessidade da manipulação e criação de tipos genéricos em sua aplicação. Mas, caso não exista a possibilidade disso, criar tipos utilizando interface
é recomendado.