Pular para o conteúdo
TypeScript

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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 = T | null e reutilize. Copiar o mesmo union em vários arquivos é dívida técnica que cresce rápido.

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.