TypedDict descreve quais chaves e valores um dicionário deve conter para ferramentas de tipagem estática. Em execução, o objeto continua sendo um dict comum. Isso o torna útil em limites simples, como uma estrutura JSON interna, sem prometer validação automática.

Definir campos obrigatórios e opcionais

from typing import NotRequired, TypedDict


class UsuarioPayload(TypedDict):
    id: int
    nome: str
    apelido: NotRequired[str]


def rotulo(usuario: UsuarioPayload) -> str:
    return usuario.get("apelido", usuario["nome"])


dados: UsuarioPayload = {"id": 7, "nome": "Ana"}
print(rotulo(dados))

A anotação ajuda o verificador a encontrar id ausente, tipo de valor incompatível ou acesso inseguro a uma chave opcional. Ela não cria construtor: UsuarioPayload(id=7, nome="Ana") apenas usa a construção comum de dict com argumentos nomeados. isinstance(dados, UsuarioPayload) não é suportado.

Representar obrigatoriedade com precisão

Por padrão, a classe é total e todas as chaves declaradas são obrigatórias. total=False permite que todas faltem, enquanto Required e NotRequired substituem essa escolha por chave.

from typing import NotRequired, Required, TypedDict


class AtualizacaoUsuario(TypedDict, total=False):
    id: Required[int]
    nome: str
    email: str
    motivo: NotRequired[str]

Nesse contrato, id precisa existir e os demais campos podem faltar. Ausência é diferente de uma chave presente com None: use str | None apenas quando nulo for um valor aceito. Uma chave que pode faltar e também aceitar nulo precisa das duas ideias, como email: NotRequired[str | None].

Marcadores por campo tornam contratos mistos mais legíveis. total=False continua prático em payloads de atualização, nos quais quase tudo é opcional. Confira a versão mínima do Python; projetos antigos podem obter os marcadores por typing_extensions.

Validar antes de estreitar o tipo

Um decodificador JSON devolve valores amplos. Não esconda o problema com cast(UsuarioPayload, bruto) antes de validar: cast() retorna o mesmo objeto e não executa verificação.

from typing import Any, TypeGuard


def eh_usuario(valor: Any) -> TypeGuard[UsuarioPayload]:
    if not isinstance(valor, dict):
        return False
    if not isinstance(valor.get("id"), int):
        return False
    if not isinstance(valor.get("nome"), str):
        return False
    apelido = valor.get("apelido")
    return apelido is None or isinstance(apelido, str)


def ler_usuario(bruto: object) -> UsuarioPayload:
    if not eh_usuario(bruto):
        raise ValueError("usuario invalido")
    return bruto

Uma validação real também verifica nomes vazios, valores permitidos, tamanhos máximos e a política para chaves desconhecidas. Atenção a bool: por ser subclasse de int, isinstance(True, int) é verdadeiro. Use type(valor) is int quando booleanos precisarem ser recusados.

TypeGuard informa ao verificador que o ramo bem-sucedido possui o tipo mais estreito. Ele não prova que a função está correta, então teste chaves ausentes, tipos errados, nulos, booleanos e dados extras. Uma biblioteca de schema pode ser adequada para estruturas grandes, mas TypedDict não deve ser vendido como validação.

Reutilizar formatos e consumir com segurança

Herança pode acrescentar chaves sem mudar o valor em runtime:

class Entidade(TypedDict):
    id: int


class Usuario(Entidade):
    nome: str
    apelido: NotRequired[str]

Mantenha hierarquias rasas. Elas descrevem conjuntos de chaves, não comportamento orientado a objetos. Para fragmentos reutilizáveis, aninhar um TypedDict dentro de outro pode representar o JSON com mais fidelidade.

Typed dictionaries possuem compatibilidade estrutural: um valor muitas vezes pode ter chaves extras e ainda atender uma função que exige um formato menor. As regras também consideram obrigatoriedade e mutabilidade, portanto acompanhe o resultado do verificador em vez de presumir as regras de subclasses comuns.

Indexar uma chave obrigatória é apropriado após a validação. Para NotRequired, verifique a presença ou use .get() tratando o fallback. Não use .get() em chave obrigatória apenas para calar um aviso, pois isso enfraquece a invariante.

Verificadores normalmente esperam chaves literais. Um loop com strings arbitrárias perde a relação entre cada chave e seu tipo. Se a iteração dinâmica dominar, Mapping[str, object], um dicionário uniforme ou um modelo de validação pode ser um contrato melhor.

Escolher a alternativa certa

Na revisão, separe chaves obrigatórias, opcionais e anuláveis. Teste um objeto completo, o mínimo válido e a ausência de cada chave obrigatória. Inclua valores com tipo errado, booleanos no lugar de inteiros, nulos e chaves extras. Rode o verificador com um erro proposital para confirmar que a anotação participa do escopo configurado.

Mantenha detalhes de transporte na borda. Se a lógica interna normaliza strings ou trata ausências repetidamente, transforme o dicionário validado em modelo de domínio. Não crie uma classe apenas para renomear um JSON estável. A escolha útil concentra incerteza na entrada e oferece um contrato simples aos chamadores.

Use TypedDict para dados já moldados como dicionário em APIs, configurações ou serialização. Use dataclass para um valor controlado pela aplicação com métodos, padrões, campos derivados ou igualdade relevante. Use Protocol para descrever comportamento e atributos em vez de chaves. Use um parser explícito ou schema em runtime quando entrada não confiável precisa ser aceita ou rejeitada.

Uma fronteira saudável decodifica o JSON, valida, devolve uma estrutura anotada com precisão e deixa a análise estática ajudar o código interno. Assim, evidência em execução fica na entrada e garantias de desenvolvimento atuam na parte confiável.

NotRequired marca uma chave que pode faltar. Required faz o inverso em uma definição criada com total=False. Prefira esses marcadores por campo, pois eles deixam o contrato mais visível do que tornar todo o dicionário opcional.

Não use TypedDict como prova de que uma resposta HTTP é confiável. Primeiro valide se o valor é um objeto, se as chaves existem e se os tipos e limites atendem ao contrato. Depois, passe a estrutura validada para o restante da aplicação.

Se o objeto precisa de invariantes, métodos ou identidade própria, considere uma dataclass. O artigo sobre type hints em Python mostra como integrar essas anotações ao fluxo de análise estática.

A documentação oficial de TypedDict, consultada em 22 de julho de 2026, detalha herança, genericidade e introspecção de chaves obrigatórias e opcionais.