Programming Language

Tipos Avançados de TypeScript

Utility types, conditional types e mapped types permitem transformar e compor tipos com precisão. Veja como eles funcionam e quando utilizá-los.

intermediate16 min readUpdated 15 de set. de 2026
typescript
type Users = {
  ada: { age: 36 };
  bob: { age: 28 };
};

type UserNames = keyof Users;
type Ages = Users[UserNames];
Utility types
Transformações de tipos nativas (Partial, Pick, Record)
Conditional types
T extends U ? X : Y
Mapped types
Transformam propriedades de um tipo existente
Template literals
Manipulação de strings em nível de tipo
Palavra-chave infer
Extrai tipos de dentro de outros tipos
Condicionais distributivas
Aplicam condições a cada membro de uma union

Por que importa

Por que tipos avançados são importantes

Transformação de tipos

Construa novos tipos a partir de tipos existentes sem duplicar definições. Altere, filtre e remodele tipos para atender às suas necessidades.

Contratos precisos

Modele dados complexos com tipos exatos que capturam erros que outros deixariam passar. Discriminated unions, tipos exatos e branded types.

Menos repetição

Derive tipos automaticamente em vez de manter definições paralelas. Uma única fonte de verdade, múltiplos tipos derivados.

O panorama completo

Os três pilares da transformação de tipos

Utility types, conditional types e mapped types são as ferramentas que permitem construir qualquer tipo a partir de tipos existentes sem repetição de código.

Utility types

Transformações nativas

Partial, Required, Pick, Omit, Record, Extract, Exclude e outros tipos padrão que modificam tipos existentes.

Conditional types

Lógica em nível de tipo

If/else em nível de tipo. T extends U ? X : Y permite ramificar tipos com base em condições.

Mapped types

Transformação de propriedades

Itera sobre as chaves de um tipo e transforma cada propriedade. A base da maioria dos utility types.

Tipos avançados em resumo

O que você pode construir

Partial<T>

Torna todas as propriedades opcionais.

Required<T>

Torna todas as propriedades obrigatórias.

Pick<T, K>

Extrai um subconjunto de propriedades.

Omit<T, K>

Remove propriedades específicas.

Record<K, V>

Cria um tipo de objeto com chaves K e valores V.

Extract<U>

Extrai membros de uma union que correspondem a um tipo.

Uma breve historia

De aliases simples à programação em nível de tipo

  1. 2016

    Chegada dos Utility types

    O TypeScript 2.1 introduz mapped types e utilitários nativos como Partial, Readonly e Pick.

    16
  2. 2018

    Lançamento dos Conditional types

    O TypeScript 2.8 adiciona conditional types, permitindo lógica em nível de tipo e a palavra-chave infer.

    18
  3. 2019

    Tipos recursivos

    O TypeScript 4.1 habilita conditional types recursivos e template literal types.

    19
  4. 2021

    Template literal types

    A manipulação de strings em nível de tipo abre novas possibilidades para o design de APIs.

    21
  5. 2023

    Operador satisfies

    O TypeScript 4.9 adiciona o satisfies para validar valores sem perder tipos literais.

    23
  6. Hoje

    Programação em nível de tipo

    Tipos avançados são essenciais para bibliotecas, clientes de API e estados de aplicação complexos.

    Hoje

O guia completo

Tipos Avançados de TypeScript: Tudo que voce precisa saber

O que são tipos avançados de TypeScript?

Tipos avançados são as ferramentas que permitem transformar, compor e manipular tipos no nível de tipagem. Em vez de definir manualmente tipos paralelos para cada variação, você os deriva automaticamente de tipos já existentes.

Se o básico fornece os tipos e os generics permitem escrever código reutilizável, os tipos avançados permitem construir um sistema de tipos que descreve seus dados com precisão — capturando erros que abordagens mais simples deixariam passar.

Os três pilares são utility types (transformações nativas), conditional types (lógica no nível de tipo) e mapped types (transformação de propriedades). Juntos, eles formam uma pequena linguagem para trabalhar com tipos.

Utility types

O TypeScript vem com tipos integrados que modificam outros tipos:

Partial e Required

interface User {
  id: number;
  name: string;
  email: string;
}

// All properties optional
type UserUpdate = Partial<User>;
// { id?: number; name?: string; email?: string; }

// All properties required
type StrictUser = Required<Partial<User>>;
// { id: number; name: string; email: string; }

Pick e Omit

// Extract specific properties
type UserPreview = Pick<User, "id" | "name">;
// { id: number; name: string; }

// Remove specific properties
type UserWithoutEmail = Omit<User, "email">;
// { id: number; name: string; }

Record

// Create object type with specific keys and values
type Scores = Record<string, number>;
// { [key: string]: number }

const scores: Scores = { math: 95, science: 87 };

// With union keys
type StatusMap = Record<"idle" | "loading" | "done", string>;

Extract e Exclude

type Status = "idle" | "loading" | "success" | "error";

// Keep only matching members
type ActiveStatus = Extract<Status, "loading" | "success">;
// "loading" | "success"

// Remove matching members
type InactiveStatus = Exclude<Status, "loading" | "success">;
// "idle" | "error"

ReturnType e Parameters

function createUser(name: string, age: number) {
  return { name, age, id: Date.now() };
}

type User = ReturnType<typeof createUser>;
// { name: string; age: number; id: number }

type Args = Parameters<typeof createUser>;
// [string, number]

NonNullable

type Maybe = string | null | undefined;
type Definite = NonNullable<Maybe>;
// string

Mapped types

Mapped types iteram sobre as chaves de um tipo existente e transformam cada propriedade:

type ReadOnly<T> = {
  readonly [K in keyof T]: T[K];
};

type MutableUser = ReadOnly<User>;
// All properties are readonly

Adicionando modificadores

// Add optional
type Optional<T> = {
  [K in keyof T]?: T[K];
};

// Remove optional
type Concrete<T> = {
  [K in keyof T]-?: T[K];
};

// Remove readonly
type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};

Os operadores - e + removem ou adicionam modificadores durante o mapeamento.

Remapeamento de chaves com as

O TypeScript 4.1+ permite que você remapeie chaves durante o mapeamento:

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// { getId: () => number; getName: () => string; getEmail: () => string; }

Tipos condicionais

Tipos condicionais expressam lógica no nível de tipos:

type IsString<T> = T extends string ? true : false;

type A = IsString<"hello">; // true
type B = IsString<42>;      // false

A palavra-chave infer

infer extrai um tipo de dentro de outro tipo:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type Fn = () => string;
type Result = ReturnType<Fn>; // string

Exemplos práticos

// Extract array element type
type ElementOf<T> = T extends (infer E)[] ? E : never;
type Num = ElementOf<number[]>; // number

// Unwrap promises
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type Deep = Awaited<Promise<Promise<string>>>; // string

// Extract object property types
type ValuesOf<T> = T[keyof T];
type UserValues = ValuesOf<User>; // number | string

Tipos condicionais distributivos

Quando um tipo condicional é distribuído sobre uma union, cada membro é verificado separadamente:

type ToArray<T> = T extends any ? T[] : never;

type Result = ToArray<string | number>;
// string[] | number[] — not (string | number)[]

Isso é útil para tipos como Extract e Exclude que filtram membros de uma union.

Template literal types

Template literal types manipulam strings no nível de tipo:

type EventName<T extends string> = `on${Capitalize<T>}`;

type ClickEvent = EventName<"click">; // "onClick"
type FocusEvent = EventName<"focus">; // "onFocus"

Com mapped types

type EventHandlers<T extends string> = {
  [K in T as `on${Capitalize<K>}`]: () => void;
};

type MouseEvents = EventHandlers<"click" | "hover" | "focus">;
// { onClick: () => void; onHover: () => void; onFocus: () => void; }

String pattern matching

type CSSProperty = `${string}-${string}`;
type ValidCSS = CSSProperty; // any string with a hyphen

Discriminated unions

Discriminated unions são o padrão avançado mais importante para a modelagem de estado:

type RequestState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: string };

function handleState(state: RequestState<User>) {
  switch (state.status) {
    case "idle":
      return "Ready";
    case "loading":
      return "Loading...";
    case "success":
      return state.data.name; // TypeScript knows data exists
    case "error":
      return state.error;    // TypeScript knows error exists
  }
}

A propriedade status é o discriminante. O TypeScript faz o narrowing do tipo automaticamente em cada ramificação.

Branded types

Branded types evitam a mistura de tipos que possuem a mesma estrutura:

type UserId = string & { readonly __brand: unique symbol };
type OrderId = string & { readonly __brand: unique symbol };

function branded<T extends string>(value: T): T & { readonly __brand: unique symbol } {
  return value as any;
}

const userId = branded<UserId>("user-123");
const orderId = branded<OrderId>("order-456");

function getUser(id: UserId) { /* ... */ }
getUser(userId);  // OK
getUser(orderId); // Error: OrderId is not assignable to UserId

Melhores práticas

  • Use utility types em vez de duplicar definições de tipos manualmente.
  • Prefira discriminated unions em vez de type assertions para a modelagem de estados.
  • Construa tipos a partir de peças pequenas e compostíveis, em vez de definições monolíticas e extensas.
  • Use conditional types com moderação — se um tipo estiver difícil de ler, simplifique a API.
  • Use infer para extrair tipos de bibliotecas em vez de tipar manualmente os valores de retorno.
  • Mantenha a fonte da verdade em um único lugar e derive todo o restante.
  • Use branded types quando precisar de nominal typing para IDs ou valores semelhantes.
  • Trate tipos complexos como último recurso — tipos simples são mais fáceis de manter.

Erros comuns

  • Over-engineering de tipos quando tipos mais simples resolveriam.
  • Criar tipos condicionais profundamente aninhados que são impossíveis de depurar.
  • Usar asserções as em vez de um type narrowing adequado.
  • Não utilizar utility types, resultando em definições de tipos duplicadas.
  • Tornar os tipos complexos demais para o benefício que proporcionam.
  • Esquecer que os tipos são removidos no runtime — não há verificação de tipos em tempo de execução.
  • Não documentar tipos complexos com comentários que expliquem a intenção.

O que aprender a seguir

Agora você compreende tipos avançados: utility types, conditional types, mapped types e template literals. A partir daqui, o próximo passo natural é TypeScript para os fundamentos — annotations, inference, interfaces e generics. Escolha um projeto, refatore alguns tipos e deixe a prática acumular.

Utility types vs definições manuais

Utility types derivam de tipos existentes, mantendo uma única fonte de verdade. Definições manuais duplicam e divergem com o tempo.

Preferir
interface User {
  id: number;
  name: string;
  email: string;
}

type UserUpdate = Partial<User>;
type UserPreview = Pick<User, "id" | "name">;
Evitar
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserUpdate {
  id?: number;
  name?: string;
  email?: string;
}

Discriminated unions vs type assertions

Discriminated unions fornecem informações suficientes para o TypeScript estreitar (narrow) os tipos automaticamente.

Preferir
type Result =
  | { ok: true; data: User }
  | { ok: false; error: string };

function handle(result: Result) {
  if (result.ok) {
    console.log(result.data);
  }
}
Evitar
interface Result {
  ok: boolean;
  data?: User;
  error?: string;
}

function handle(result: Result) {
  const user = result.data as User;
}

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Advanced Types?

Nosso tutorial interativo te guia por Advanced Types passo a passo — com quizzes e codigo real que voce pode executar no navegador.