No TypeScript, temos duas opções para definir tipos: types (tipos) e interfaces. Uma dúvida muito comum é qual delas devemos usar.
A resposta, como muitas em programação, é: depende. Em alguns casos, uma pode ser claramente mais adequada que a outra, mas em muitos outros, elas são intercambiáveis.
Neste artigo, vamos explorar as principais diferenças e semelhanças entre types e interfaces e quando é mais apropriado usar cada uma.
O básico sobre tipos e interfaces
Tipos e “type aliases” (apelidos de tipo)
No TypeScript, type é uma palavra-chave usada para definir a estrutura dos dados. Alguns tipos básicos incluem:
- String (texto)
- Boolean (verdadeiro ou falso)
- Number (números)
- Array (listas)
- Tuple (tuplas)
- Enum (enumerações)
Esses tipos servem para diferentes finalidades, e você pode escolher o que se encaixa melhor no seu caso.
Um type alias é basicamente um nome alternativo para um tipo já existente. Ele não cria um novo tipo, mas fornece um jeito mais fácil de se referir a um tipo.
Exemplo:
type MeuNumero = number;
type Usuario = {
id: number;
nome: string;
email: string;
};
Aqui, criamos dois aliases: um para números e outro para representar um usuário.
Interfaces no TypeScript
Já uma interface define um “contrato” que um objeto precisa seguir. Veja o exemplo:
interface Cliente {
nome: string;
endereco: string;
}
Este contrato exige que todo objeto do tipo Cliente
tenha as propriedades nome
e endereco
. Podemos expressar a mesma ideia usando um type:
type Cliente = {
nome: string;
endereco: string;
};
Diferenças entre tipos e interfaces
Agora que vimos que ambos podem ser usados para definir estruturas, é importante entender as diferenças. Há casos em que type ou interface fazem mais sentido. Vamos ver alguns exemplos.
Tipos primitivos
Tipos primitivos, como string
, number
, boolean
, null
, e undefined
, são embutidos no TypeScript. Podemos criar aliases para esses tipos com type, mas interfaces não podem ser usadas para isso.
Exemplo:
type Endereco = string;
Tipos de união
Um tipo de união permite que um valor seja de vários tipos:
type Transporte = 'Carro' | 'Bicicleta' | 'Ônibus' | 'A pé';
As uniões só podem ser definidas com type. Interfaces não têm essa capacidade.
Tipos de funções
Tanto types quanto interfaces podem ser usados para definir o tipo de uma função, mas o type tem uma sintaxe mais concisa:
type Soma = (a: number, b: number) => number;
Com interface:
interface Soma {
(a: number, b: number): number;
}
No geral, type é preferido aqui por ser mais curto e direto.
Vantagens específicas das interfaces
Uma das funcionalidades exclusivas das interfaces é o merging de declarações. Isso significa que podemos declarar uma mesma interface várias vezes, e o TypeScript automaticamente une todas as declarações.
Exemplo:
interface Cliente {
nome: string;
}
interface Cliente {
idade: number;
}
const cliente: Cliente = {
nome: 'João',
idade: 30
};
Já com types, isso não é possível. Se tentarmos declarar um type mais de uma vez, ocorrerá um erro.
Extensão: Interfaces vs. Types
Uma interface pode ser estendida para herdar propriedades de outra interface:
interface ClienteVIP extends Cliente {
beneficios: string[];
}
Para fazer algo similar com types, usamos o operador de interseção (&
):
type ClienteVIP = Cliente & { beneficios: string[] };
Ambos podem ser estendidos, mas interfaces costumam ser mais claras, especialmente em grandes projetos.
Conflitos ao estender
Outro ponto importante é como conflitos são tratados. Ao estender interfaces, não podemos usar o mesmo nome de propriedade duas vezes:
interface Pessoa {
getPermissao: () => string;
}
interface Funcionario extends Pessoa {
getPermissao: () => string[];
}
// Erro: conflito de tipos
Com types, a abordagem é diferente: eles mesclam as propriedades em vez de gerar erro, o que pode ser útil em alguns casos:
type Pessoa = {
getPermissao: (id: string) => string;
};
type Funcionario = Pessoa & {
getPermissao: (id: string[]) => string[];
};
Quando usar types vs interfaces
As interfaces são ideais quando precisamos de declaration merging ou quando seguimos um estilo mais orientado a objetos. Além disso, o TypeScript costuma ser mais eficiente ao trabalhar com interfaces, já que ele armazena em cache as relações entre elas.
Por outro lado, os types são mais flexíveis e poderosos, especialmente quando precisamos de recursos avançados como tipos condicionais, uniões e interseções. Eles também são mais adequados para sobrecarga de funções e manipulação de tipos complexos.
Conclusão
Tipos e interfaces são ferramentas essenciais no TypeScript, e ambos têm suas vantagens. A escolha entre eles depende muito do caso de uso específico e das preferências pessoais. No geral, types são mais versáteis e expressivos, mas interfaces oferecem algumas vantagens de performance e legibilidade em projetos maiores. A chave é entender as diferenças e saber quando usar cada um.
Se você tiver dúvidas ou preferências, sinta-se à vontade para compartilhar nos comentários!