Type Alias no TypeScript: Guia Prático
Type alias vai além de dar nomes a tipos. Union types, intersection, literal types e composição. Tudo com exemplos que você aplica agora.
Por que isso é importante
Type Alias no TypeScript: Guia Prático. Type alias vai além de dar nomes a tipos. Union types, intersection, literal types e composição. Tudo com exemplos que você aplica agora.
O Que É Type Alias no TypeScript
Type alias é um nome customizado para qualquer tipo no TypeScript. Pode ser simples como dar um nome pra string, ou complexo como criar uma combinação de tipos condicionais, unions e intersections. A flexibilidade é absurda.
A diferença entre type e interface é sutil mas importante. Interface foi feita pra descrever a forma de objetos. Type alias foi feito pra tudo: primitivos, unions, tuplas, funções, tipos condicionais, template literals. É mais flexível e cobre cenários que interface simplesmente não consegue.
Um detalhe que confunde muita gente: type não cria um novo tipo. Ele cria um apelido. type ID = string não inventa um tipo novo, só dá o nome ID pro tipo string. Qualquer lugar que aceita string aceita ID e vice-versa. É transparente pro compilador.
Mas esse "apelido" tem poder imenso. Dá pra compor tipos complexos, extrair tipos de objetos, criar tipos condicionais e muito mais. Quando você domina type alias, desbloqueia um nível de tipagem que transforma seu código.
Na prática, type alias e interface se complementam. A convenção mais aceita é: use interface pra objetos e classes, use type pra todo o resto. Mas não se estresse com isso no começo. Os dois resolvem o problema e o TypeScript aceita ambos na maioria das situações.
Como Usar Type Alias Passo a Passo
Cada passo abre uma possibilidade nova. Do mais simples ao mais sofisticado, vamos construir seu repertório de tipagem avançada.
- Passo 1 - Type alias básico: Use a keyword type seguida do nome, sinal de igual e o tipo. type ID = string; type Preco = number;. Agora ID e Preco são reutilizáveis em todo o projeto. O nome documenta a intenção melhor que o tipo primitivo.
- Passo 2 - Union types: Combine tipos com pipe. type Status = "ativo" | "inativo" | "pendente";. A variável só aceita um desses valores. Ideal pra enums de string, estados de componentes, roles de usuário.
- Passo 3 - Type alias para objetos: type Usuario = { nome: string; email: string; };. Funciona parecido com interface, mas não dá pra estender com extends nem usar declaration merging. Use quando precisa de union ou intersection depois.
- Passo 4 - Intersection types: Combine tipos com &. type Admin = Usuario & { permissoes: string[]; };. Admin tem tudo de Usuario mais permissoes. É a "herança" do type alias, e dá pra combinar quantos tipos quiser.
- Passo 5 - Literal types: Restrinja a valores específicos. type Direcao = "norte" | "sul" | "leste" | "oeste";. O compilador barra qualquer valor fora dessa lista. Autocomplete do editor mostra as opções disponíveis.
- Passo 6 - Tuplas: type Coordenada = [number, number];. Arrays com tamanho fixo e tipos por posição. Perfeito pra retornos de funções com múltiplos valores e pra coordenadas, ranges, pares chave-valor.
Exemplos Práticos de Type Alias
Vamos ver type alias em cenários que você encontra em qualquer projeto real. Cada exemplo mostra um pattern diferente.
Union Types: Valores Restritos
// Status de pedido - só aceita esses valores
type StatusPedido = "pendente" | "pago" | "enviado" | "entregue" | "cancelado";
function atualizarPedido(id: number, status: StatusPedido): void {
console.log(`Pedido ${id} atualizado para: ${status}`);
}
atualizarPedido(1, "pago"); // OK
atualizarPedido(2, "enviado"); // OK
// atualizarPedido(3, "devolvido"); // Error! "devolvido" não está no union
// Union com tipos diferentes
type Resposta = string | number | boolean;
function processar(valor: Resposta): string {
if (typeof valor === "string") return `Texto: ${valor}`;
if (typeof valor === "number") return `Número: ${valor}`;
return `Boolean: ${valor}`;
}
Union types de strings são tão úteis que substituem enums na maioria dos casos. A vantagem sobre enum é que não gera código JavaScript extra e funciona melhor com autocomplete. Quando alguém digita status = ", o editor já mostra todas as opções disponíveis. Produtividade pura.
Intersection Types: Composição de Tipos
// Tipos base
type DadosPessoais = {
nome: string;
cpf: string;
dataNascimento: Date;
};
type DadosProfissionais = {
cargo: string;
empresa: string;
salario: number;
};
type Endereco = {
rua: string;
cidade: string;
estado: string;
cep: string;
};
// Intersection: combina todos os tipos
type FuncionarioCompleto = DadosPessoais & DadosProfissionais & Endereco;
const funcionario: FuncionarioCompleto = {
nome: "Ana Paula",
cpf: "123.456.789-00",
dataNascimento: new Date("1990-05-15"),
cargo: "Tech Lead",
empresa: "StartupXYZ",
salario: 18000,
rua: "Av. Paulista, 1000",
cidade: "São Paulo",
estado: "SP",
cep: "01310-000",
};
Intersection é composição. Você monta tipos complexos a partir de peças menores e reutilizáveis. DadosPessoais pode ser usado sozinho em formulários de cadastro. DadosProfissionais pode ser usado no módulo de RH. E FuncionarioCompleto combina os dois quando precisa de tudo junto. Reutilização de tipos elimina duplicação.
Literal Types e Discriminated Unions
// Literal types: valores exatos
type Tema = "claro" | "escuro" | "sistema";
type Tamanho = "P" | "M" | "G" | "GG";
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
// Discriminated union - cada tipo tem um campo discriminador
type Notificacao =
| { tipo: "email"; destinatario: string; assunto: string; corpo: string }
| { tipo: "sms"; telefone: string; mensagem: string }
| { tipo: "push"; token: string; titulo: string; corpo: string };
function enviarNotificacao(notif: Notificacao): void {
switch (notif.tipo) {
case "email":
console.log(`Email para ${notif.destinatario}: ${notif.assunto}`);
break;
case "sms":
console.log(`SMS para ${notif.telefone}: ${notif.mensagem}`);
break;
case "push":
console.log(`Push para ${notif.token}: ${notif.titulo}`);
break;
}
}
Discriminated unions são um dos patterns mais poderosos do TypeScript. O campo tipo funciona como discriminador: dentro de cada case do switch, o TypeScript sabe exatamente quais propriedades existem. Sem casts, sem verificações manuais. O compilador faz o narrowing automaticamente. Isso é tipagem inteligente de fato.
Tuplas e Function Types
// Tuplas: arrays com tipos por posição
type Coordenada = [number, number];
type NomeIdade = [string, number];
type ResultadoAPI = [boolean, string, number]; // sucesso, mensagem, código
const ponto: Coordenada = [10, 20];
const pessoa: NomeIdade = ["João", 28];
const resultado: ResultadoAPI = [true, "OK", 200];
// Destructuring tipado
const [sucesso, mensagem, codigo] = resultado;
// sucesso: boolean, mensagem: string, codigo: number
// Function types com type alias
type Validador = (valor: string) => boolean;
type AsyncHandler = (req: Request, res: Response) => Promise<void>;
const validarEmail: Validador = (email) => {
return email.includes("@") && email.includes(".");
};
console.log(validarEmail("test@email.com")); // true
console.log(validarEmail("invalido")); // false
Tuplas são arrays com superpoderes. Cada posição tem um tipo específico e o tamanho é fixo. Quando você desestrutura, cada variável já tem o tipo certo. Perfeito pra retornos de funções onde um array faz mais sentido que um objeto (como o useState do React que retorna [valor, setter]).
Template Literal Types
// Combinar literal types com template strings
type Cor = "vermelho" | "azul" | "verde";
type Tonalidade = "claro" | "escuro";
// Gera: "vermelho-claro" | "vermelho-escuro" | "azul-claro" ...
type CorCompleta = `${Cor}-${Tonalidade}`;
const cor: CorCompleta = "azul-escuro"; // OK
// const errada: CorCompleta = "amarelo-claro"; // Error!
// Muito usado em CSS-in-JS e APIs
type Evento = "click" | "hover" | "focus";
type Handler = `on${Capitalize<Evento>}`; // "onClick" | "onHover" | "onFocus"
Template literal types geram combinações automaticamente. Se Cor tem 3 valores e Tonalidade tem 2, CorCompleta tem 6 valores. O TypeScript calcula todas as combinações possíveis. Isso é extremamente útil em design systems, APIs com padrões de nomenclatura e CSS-in-JS. Usa com moderação: se as combinações explodirem, o compilador fica lento.
Quando Usar Type vs Interface
A regra prática é direta. Use interface quando vai modelar a forma de um objeto ou classe. Use type quando precisa de union, intersection, tupla, tipo primitivo nomeado ou qualquer composição que interface não suporta.
Interface suporta declaration merging: se você declara a mesma interface duas vezes, o TypeScript combina as propriedades. Isso é importante pra bibliotecas que precisam ser estendidas. Type alias não suporta isso. Uma vez declarado, não dá pra adicionar propriedades depois.
Na dúvida, comece com interface pra objetos e troque pra type quando encontrar uma limitação. Muitos times adotam a convenção de interface pra tudo e só usam type quando precisa de union. Tanto faz, desde que o time todo siga a mesma convenção. Consistência importa mais que a escolha em si.
Erros Comuns com Type Alias
Armadilhas que travam devs
Usar type pra tudo, inclusive objetos simples: se o tipo descreve a forma de um objeto e pode precisar de extends ou declaration merging no futuro, interface é mais adequada. Type é melhor pra unions, primitivos e composições.
Criar unions gigantes sem discriminador: union de 10 objetos sem um campo comum que identifique cada tipo vira pesadelo. Sempre adicione um campo tipo ou kind como discriminador. Sem ele, o narrowing dentro de funções é manual e propenso a erro.
Esquecer que intersection combina, não escolhe: type A & B significa que o objeto precisa ter TODAS as propriedades de A E B. Não é "A ou B". Pra isso, use union (A | B). Confundir & com | é um dos erros mais comuns entre iniciantes.
Não reutilizar type alias: se você repete string | number | null em 10 lugares, crie type Nullable
Template literal types complexos demais: são poderosos mas podem gerar tipos com centenas de combinações. Use com moderação pra não sobrecarregar o compilador e não confundir quem lê o código depois.
Checklist de Type Alias
- Type alias com nomes descritivos em PascalCase
- Union types com discriminador para objetos complexos
- Intersection types para compor tipos sem duplicação
- Literal types para valores restritos (status, roles, temas)
- Tuplas para retornos de função com múltiplos valores
- Function types extraídos em type alias reutilizável
- Nenhum union repetido em mais de 2 lugares (extraia pra type)
- Template literal types apenas quando a combinação é finita e útil
Tipos Avançados na Prática
Type alias é só a porta de entrada pra tipagem avançada no TypeScript. No CrazyStack, você usa unions, intersections, generics e utility types num projeto real com Node.js e React. Não é código de playground: é SaaS com autenticação, pagamento e deploy.
Cada decisão de tipo no curso tem contexto. Você entende o porquê, não só o como. É o que separa quem sabe TypeScript de quem sabe usar TypeScript de fato.
Perguntas frequentes
O Que É Type Alias no TypeScript
Type alias é um nome customizado para qualquer tipo no TypeScript. Pode ser simples como dar um nome pra string, ou complexo como criar uma combinação de tipos condicionais, unions e intersections. A flexibilidade é absurda. A diferença entre type e interface é sutil mas importante. Interface foi feita pra descrever a forma de objetos. Type alias foi feito pra tudo: primitivos, unions, tuplas, funções, tipos condicionais, template literals. É mais flexível e cobre cenários que interface simplesmente não consegue. Um detalhe que confunde muita gente: type não cria um novo tipo. Ele cria um apelido. type ID = string não inventa um tipo novo, só dá o nome ID pro tipo string. Qualquer lugar que aceita string aceita ID e vice-versa. É transparente pro compilador.
Como Usar Type Alias Passo a Passo
Cada passo abre uma possibilidade nova. Do mais simples ao mais sofisticado, vamos construir seu repertório de tipagem avançada.
Quando Usar Type vs Interface
A regra prática é direta. Use interface quando vai modelar a forma de um objeto ou classe. Use type quando precisa de union, intersection, tupla, tipo primitivo nomeado ou qualquer composição que interface não suporta. Interface suporta declaration merging: se você declara a mesma interface duas vezes, o TypeScript combina as propriedades. Isso é importante pra bibliotecas que precisam ser estendidas. Type alias não suporta isso. Uma vez declarado, não dá pra adicionar propriedades depois. Na dúvida, comece com interface pra objetos e troque pra type quando encontrar uma limitação. Muitos times adotam a convenção de interface pra tudo e só usam type quando precisa de union. Tanto faz, desde que o time todo siga a mesma convenção. Consistência importa mais que a escolha em si.