Gerando tipos TypeScript a partir de JSON: um guia prático
Escrever à mão uma interface TypeScript para uma resposta de API com 40 campos é tedioso e propenso a erros — um typo num nome de campo quebra silenciosamente a segurança de tipos em vez de gerar um erro de compilação. Gerar a interface diretamente de uma amostra JSON real é mais rápido e mais preciso, desde que você entenda onde a inferência precisa adivinhar.
Como funciona a inferência JSON-para-TypeScript
Um gerador percorre a árvore de valores JSON e mapeia cada tipo JavaScript para seu equivalente TypeScript: string continua string, number continua number, boolean continua boolean, null vira null (ou é mesclado numa union), arrays viram T[] onde T é inferido dos elementos, e objetos viram interfaces aninhadas.
{
"id": 42,
"email": "ada@example.com",
"isActive": true,
"roles": ["admin", "editor"],
"profile": {
"displayName": "Ada",
"avatarUrl": null
}
}interface Root {
id: number;
email: string;
isActive: boolean;
roles: string[];
profile: {
displayName: string;
avatarUrl: string | null;
};
}Onde a inferência precisa adivinhar
Campos opcionais vs. sempre presentes: uma única amostra JSON não consegue dizer ao gerador se avatarUrl às vezes está totalmente ausente (o que deveria ser avatarUrl?: string | null) ou sempre presente mas às vezes null. Alimente o gerador com algumas amostras representativas, ou marque manualmente um campo como opcional após a geração, se você sabe que a API o omite em certas condições.
Números que são IDs vs. quantidades: o JSON tem um único tipo numérico, mas o TypeScript não consegue distinguir um ID inteiro de um preço de ponto flutuante sem contexto extra. Alguns geradores oferecem branded types ou unions literais para isso; a maioria apenas emite number e deixa a distinção com você.
Arrays vazios: um array sem exemplos dentro ("tags": []) não dá ao gerador nada de onde inferir o tipo do elemento — ele tipicamente recorre a unknown[] ou any[]. Aponte o gerador para uma amostra em que o array esteja populado, ou anote-o manualmente depois.
Unions de literais de string: um campo status que é sempre um de "pending" | "active" | "closed" será inferido como string comum, a menos que o gerador veja todos os valores possíveis na amostra — e mesmo assim, a maioria dos geradores usa por padrão o tipo mais amplo string, a não ser que você ative explicitamente a inferência de union literal.
Datas: o JSON não tem tipo de data — timestamps são sempre strings (ISO 8601) ou números (epoch Unix). Um gerador tipará um campo de data como string ou number, não como Date; você ainda precisa analisá-lo por conta própria após o fetch.
A mesma ideia em outras linguagens
A lógica de inferência — percorrer a árvore, mapear tipos, nomear objetos aninhados — é a mesma independente da linguagem-alvo; apenas a sintaxe de saída muda. Um struct Go recebe o mesmo mapeamento de campos com struct tags para os nomes das chaves JSON; uma dataclass Python recebe type hints e um wrapper opcional Optional[...]; uma classe Java ou C# recebe campos tipados e getters/setters ou records. Se seu time trabalha em múltiplas linguagens contra a mesma API, gerar tipos para cada uma a partir da mesma amostra JSON mantém todas honestas entre si.
type Root struct {
ID int `json:"id"`
Email string `json:"email"`
IsActive bool `json:"isActive"`
Roles []string `json:"roles"`
Profile struct {
DisplayName string `json:"displayName"`
AvatarURL *string `json:"avatarUrl"`
} `json:"profile"`
}Antes de confiar nos tipos gerados
Tipos gerados são um forte ponto de partida, não um contrato final. Antes de commitá-los: confirme os campos opcionais contra a documentação real da API (não apenas uma amostra), substitua campos string vagos que na verdade são enums por unions literais, verifique se campos de array vazio receberam um tipo de elemento real a partir de uma amostra melhor, e gere novamente sempre que a API upstream adicionar ou renomear um campo, em vez de remendar a interface à mão.
FAQ
- Um gerador JSON-para-TypeScript consegue lidar com um campo que às vezes é string e às vezes é number?
- Sim, se ele vir ambas as variantes nas amostras que recebe — ele deve inferir string | number. Com apenas uma amostra, ele só consegue tipar o que viu. Esse é o principal motivo para gerar a partir de múltiplos payloads representativos, e não de um único exemplo de caminho feliz.
- Interfaces geradas devem usar `interface` ou `type`?
- Funcionalmente quase idênticos para este caso de uso. `interface` é mais comum para formas de objeto e suporta declaration merging; `type` é mais flexível para unions e intersections. Ambos funcionam para formas de resposta de API — escolha o que corresponde à convenção existente do seu codebase.
- Como manter os tipos gerados em sincronia conforme a API evolui?
- Trate a geração como uma etapa repetível, não um copy-paste único: mantenha uma amostra real de resposta versionada no repositório (ou obtida de um endpoint de staging) e gere a interface novamente sempre que a amostra mudar, em vez de editar à mão o arquivo gerado. Alguns times ligam isso ao CI para capturar desvios automaticamente.
- Isso funciona para JSON profundamente aninhado ou recursivo, como uma estrutura de árvore?
- Aninhamento profundo gera interfaces aninhadas sem problema. Estruturas realmente recursivas (um comentário que pode conter respostas da mesma forma) precisam de um tipo autorreferencial, que a maioria dos geradores não infere automaticamente de uma única amostra — tipicamente você precisará escrever à mão a interface recursiva uma vez e reutilizá-la.
Experimente estas ferramentas
JSON to TypeScript →
Generate TypeScript interfaces from JSON with optional readonly modifiers and JSDoc comments.
JSON to Go →
Generate Go structs with json tags from a JSON sample, ready for encoding/json.
JSON to Python →
Generate Python TypedDict classes from a JSON sample for mypy, Pyright, and editor autocompletion.
Artigos relacionados
O que é JSON? Um guia completo para iniciantes →
JSON (JavaScript Object Notation) é um formato leve de troca de dados, fácil de ler por humanos e de analisar por máquinas. Aprenda a sintaxe, os tipos de dados e a estrutura que sustentam as APIs modernas.
A história do JSON: de 2000 a padrão da indústria →
Acompanhe o JSON desde a ideia de Douglas Crockford em 2001, passando pela adoção pelo Yahoo, até se tornar o padrão ECMA-404 que sustenta 90% das APIs modernas.
O guia completo do JSON Schema (Draft 7) →
O JSON Schema é o padrão para descrever e validar a estrutura de JSON. Aprenda as palavras-chave essenciais, construa um schema real de API e aplique as melhores práticas.