---
title: "TypeScript avançado: Utility Types e padrões de tipagem que você precisa conhecer"
slug: "typescript-advanced-utility-types"
author: "Mateus Cavalcanti"
publishedAt: "2026-09-13T00:16:03.914Z"
updatedAt: "2026-09-13T00:16:03.915Z"
category: "Frontend"
tags:
  - "JavaScript"
  - "Tipagem"
  - "TypeScript"
  - "Web Development"
---

# TypeScript avançado: Utility Types e padrões de tipagem que você precisa conhecer

O sistema de tipos do TypeScript vai muito além de anotações básicas. Usar os recursos corretos de tipagem não apenas previne bugs em tempo de compilação, mas também documenta a arquitetura e reduz duplicação de contratos.

Neste artigo, exploramos desde os Utility Types essenciais até padrões de tipagem avançada com tipos condicionais e inferência.

---

## 1. O kit essencial de Utility Types

### `Partial<T>` e `Required<T>`
Ideais para cenários de atualização parcial (patch) ou para garantir que campos opcionais sejam obrigatórios em etapas específicas do fluxo:

```ts
interface User {
  id: string;
  name: string;
  email: string;
  avatarUrl?: string;
}

// Para mutações parciais (ex: PATCH /users/:id)
type UpdateUserInput = Partial<Omit<User, "id">>;

// Exige que todas as propriedades sejam definidas (ex: perfil completo)
type CompleteUserProfile = Required<User>;
```

### `Pick<T, K>` e `Omit<T, K>`
Permitem recortar ou remover propriedades de um contrato existente, garantindo que o tipo derivado continue sincronizado com o modelo original:

```ts
type PublicProfile = Pick<User, "id" | "name" | "avatarUrl">;
type CreateUserInput = Omit<User, "id">;
```

### `Record<K, V>`
Essencial para mapear dicionários, tabelas de tradução ou handlers:

```ts
type Role = "admin" | "editor" | "viewer";

interface PermissionConfig {
  canWrite: boolean;
  canDelete: boolean;
}

const rolePermissions: Record<Role, PermissionConfig> = {
  admin: { canWrite: true, canDelete: true },
  editor: { canWrite: true, canDelete: false },
  viewer: { canWrite: false, canDelete: false },
};
```

---

## 2. Tipagem Avançada: Elevando o nível

### Conditional Types e a palavra-chave `infer`
Tipos condicionais permitem criar lógicas do tipo *"se T estende U, então X, senão Y"*. Com o operador `infer`, podemos extrair tipos internos de dentro de estruturas genéricas, como funções, promises ou tuplas.

```ts
// Exemplo: Extrair o tipo resolvido de uma Promise ou retornar o próprio tipo
type FlattenPromise<T> = T extends Promise<infer U> ? FlattenPromise<U> : T;

type A = FlattenPromise<Promise<string>>; // string
type B = FlattenPromise<Promise<Promise<number>>>; // number (recursivo)

// Exemplo: Extrair o primeiro argumento de qualquer função
type FirstArgument<T> = T extends (first: infer Arg, ...rest: any[]) => any ? Arg : never;

function notifyUser(userId: string, message: string) {}
type UserIdType = FirstArgument<typeof notifyUser>; // string
```

### Template Literal Types
Introduzidos para manipular strings a nível de tipo, são perfeitos para APIs tipadas, canais de eventos e design systems:

```ts
type EventType = "user" | "order" | "invoice";
type Action = "created" | "updated" | "deleted";

// Gera automaticamente: "user:created" | "user:updated" | ...
type DomainEvent = `${EventType}:${Action}`;

function emitEvent(event: DomainEvent) {
  console.log(`Disparando: ${event}`);
}

emitEvent("user:created"); // ✅ Válido
// emitEvent("user:archived"); // ❌ Erro de compilação!
```

---

## Dicas práticas para produção

1. **Evite `any` a todo custo**: Prefira `unknown` quando não souber a estrutura de entrada, combinando com type guards (`typeof`, `instanceof` ou validação com Zod).
2. **Não crie tipos complexos prematuramente**: Comece com interfaces simples e extraia utilitários conforme duplicar código se tornar um problema real de manutenção.
3. **Use tipos para comunicar intenção de negócio**: Aliases bem nomeados tornam o código autoexplicativo para qualquer membro do time.
