kb.erickguedes.com
TypeScript: Tipagem e Produtividade

Interfaces e Types Avançados

Aula 2 de 7

Interface

Interface define a estrutura (contrato) de um objeto:

interface Usuario {
  id: number;
  nome: string;
  email: string;
}

const usuario: Usuario = {
  id: 1,
  nome: "Alice",
  email: "[email protected]",
};

extends — Herança de Interfaces

interface Animal {
  nome: string;
  idade: number;
}

interface Cachorro extends Animal {
  raca: string;
  late(): void;
}

const rex: Cachorro = {
  nome: "Rex",
  idade: 3,
  raca: "Pastor Alemão",
  late: () => console.log("Au au!"),
};

Propriedades Opcionais e Readonly

interface Config {
  readonly id: string;     // imutável após criação
  url: string;
  timeout?: number;       // opcional
  headers?: Record<string, string>;
}

const config: Config = { id: "abc123", url: "https://api.exemplo.com" };

// Erro: Cannot assign to 'id' because it is a read-only property
// config.id = "novo";

Index Signature

interface Dicionario {
  [chave: string]: string;
}

const traducoes: Dicionario = {
  hello: "olá",
  world: "mundo",
};

Type Alias vs Interface

CaracterísticaInterfaceType
extends/herançaextends& (intersection)
Declaration mergingSimNão
Union/IntersectionNãoSim
Utility types (Pick, Omit)SimSim
Tupas e primitivosNãoSim
// Type alias aceita union, tuple e primitivos:
type Status = "ativo" | "inativo";
type ParOrdenado = [number, number];
type ID = string | number;

// Declaration merging (só interface):
interface Pessoa {
  nome: string;
}
interface Pessoa {
  idade: number;
}
// Resultado: { nome: string; idade: number; }

Utility Types

interface Produto {
  id: number;
  nome: string;
  preco: number;
  descricao: string;
  categoria: string;
}

// Partial — todas as props opcionais
function atualizarProduto(id: number, dados: Partial<Produto>) {
  // dados pode ter qualquer subconjunto de Produto
}

// Required — todas as props obrigatórias
type ProdutoCompleto = Required<Partial<Produto>>;

// Pick — seleciona props específicas
type ProdutoResumo = Pick<Produto, "id" | "nome" | "preco">;

// Omit — exclui props específicas
type ProdutoSemDescricao = Omit<Produto, "descricao" | "categoria">;

// Record — tipo dicionário
type Categorias = Record<string, Produto[]>;

// Exclude — remove tipos de uma union
type Status = "ativo" | "inativo" | "pendente";
type Ativos = Exclude<Status, "inativo" | "pendente">; // "ativo"

// Extract — mantém apenas os tipos especificados
type NumerosOuStrings = string | number | boolean;
type SoStrings = Extract<NumerosOuStrings, string>; // string

satisfies Operator

satisfies verifica se uma expressão satisfaz um tipo sem alterar o tipo inferido:

type Cores = "red" | "green" | "blue";

const paleta = {
  fundo: "blue",
  texto: "white",
} satisfies Record<string, Cores>;

// paleta.fundo é inferido como "blue" (literal), não como Cores
// mas a verificação garante que só valores Cores foram usados

// Erro: Type '"white"' is not assignable to type 'Cores'

Lab: Tipos Avançados na Prática

interface User {
  id: number;
  name: string;
  email: string;
  role: "admin" | "user" | "viewer";
  createdAt: Date;
}

type UserCreate = Omit<User, "id" | "createdAt">;
type UserUpdate = Partial<UserCreate>;
type UserResponse = Pick<User, "id" | "name" | "email" | "role">;

function createUser(data: UserCreate): User {
  return {
    id: Date.now(),
    createdAt: new Date(),
    ...data,
  };
}

function updateUser(id: number, data: UserUpdate): void {
  console.log(`Atualizando usuário ${id}:`, data);
}

function listUsers(): UserResponse[] {
  return [];
}
# Verificar tipos com tsc
npx tsc --noEmit

Prefira interface para objetos/classes (declaration merging, mensagens de erro melhores). Use type para unions, tuples e primitivos.