JSON para TypeScript
Cole JSON e obtenha instantaneamente interfaces TypeScript.
Como usar
- Cole seu JSON no painel da esquerda (objeto ou array).
- Clique em Converter · as interfaces TypeScript aparecem à direita.
- Ajuste o nome raiz e ative as opções conforme necessário.
- Clique em Copiar a saída para copiar o código gerado.
Perguntas frequentes
Ele lida com objetos aninhados ?
Sim. Cada objeto aninhado recebe sua própria interface nomeada. Os elementos dos arrays também são analisados para determinar o tipo de elemento.
O que acontece com arrays de tipos mistos ?
Se um array contém elementos de tipos diferentes, o conversor usa um tipo union (por ex. string | number).
Ele suporta arrays JSON na raiz ?
Sim. Se o valor raiz é um array, o conversor analisa seus elementos e produz a interface apropriada e um alias de tipo para o array.
O que o conversor realmente faz
Ele analisa o seu JSON, percorre cada valor e gera um conjunto de declarações interface do TypeScript que descrevem o formato. Cada objeto aninhado recebe a sua própria interface nomeada, derivada da chave da propriedade pai em PascalCase (um campo user vira uma interface User). Quando dois objetos aninhados colidem no nome, o segundo recebe um sufixo numérico (User, User2). Na raiz, um array vira um alias type Root = RootItem[]; mais a interface RootItem; um objeto vira uma única interface Root (ou o nome que você puser no campo «nome raiz»).
Exemplo de entrada e saída:
// Input
{
"id": 42,
"name": "Ada",
"active": true,
"tags": ["admin", "billing"],
"profile": { "bio": "Programmer", "link": null }
}
// Output
export interface Root {
id: number;
name: string;
active: boolean;
tags: string[];
profile: Profile;
}
export interface Profile {
bio: string;
link: unknown;
}
O mapeamento de tipos JSON → TypeScript
| Valor JSON | TS gerado |
|---|---|
"hello" | string |
42 ou 3.14 | number (o TS não tem um tipo inteiro separado) |
true / false | boolean |
null | unknown (o conversor não tem como saber se o campo é anulável ou apenas ausente neste exemplo) |
[] | unknown[] |
[1, 2, 3] | number[] |
[1, "x"] | (number | string)[] |
{ "a": 1 } | interface nomeada |
Para arrays de objetos no nível raiz, o conversor mescla as chaves de todos os itens em uma única interface representativa. É uma aproximação razoável quando os itens compartilham um formato, mas perde informação quando os formatos realmente divergem (por exemplo, um array heterogêneo de eventos). Nesse caso, você precisaria escrever uma união discriminada à mão após a geração.
Por que interface para objetos e type para o array raiz
O TypeScript Handbook oficial dá uma heurística de uma linha: «Se você quiser uma heurística, use interface até precisar de recursos do type.» Ambos são tipados estruturalmente, ambos podem descrever formatos de objeto, mas interface vence para formatos de objeto porque suporta a fusão de declarações (reabrir a interface para adicionar campos), funciona de forma limpa com extends e aparece pelo nome nos erros do compilador. Os aliases type são necessários quando você precisa de uniões de primitivos, interseções de múltiplos tipos, ou nomear algo que não é um objeto, e é por isso que o array de nível raiz recebe um alias type Root = RootItem[]; em vez de uma interface.
Uma observação sobre nomenclatura: o conversor usa PascalCase sem o prefixo legado I (ou seja, User em vez de IUser). Os guias de estilo modernos de TS (o do Google, o da Microsoft, o da comunidade React) quase universalmente abandonam o prefixo. Os nomes das propriedades correspondem exatamente às chaves do JSON (camelCase se o JSON usa camelCase, snake_case se usa snake_case). As chaves que não são identificadores JS válidos (com hifens, espaços ou começando com um dígito) ficam entre aspas: "foo-bar": string;.
O que esta ferramenta não faz (sejamos honestos sobre os limites)
Um único exemplo de JSON carrega menos informação do que um schema de verdade, então várias coisas que seria bom detectar não são possíveis só a partir da entrada:
- Campos opcionais. Toda propriedade do seu exemplo vira obrigatória. Se a API real às vezes omite um campo, você precisa adicionar o
?à mão:email?: string;. Ou rode o conversor em vários exemplos e una os resultados. - Detecção de anulável. Um
nullno exemplo viraunknown; o conversor não tem como saber se o campo é genuinamente anulável (string | null) ou apenas calhou de ser null neste exemplo. Ajuste à mão com base no contrato da API. - Uniões de literais de string. Um campo de status com o valor
"active"virastring, não"active" | "inactive" | "pending". O conversor não consegue ver os outros valores. - Detecção de tipo de data. Uma string ISO 8601 como
"2024-04-12T10:00:00Z"permanece comostring. ODatedo JavaScript não é um tipo JSON. - Uniões discriminadas. Se um array raiz contém itens de formatos diferentes (eventos de tipos diferentes, registros polimórficos), o conversor mescla todas as chaves em uma só interface em vez de produzir uma união marcada. Para dados realmente heterogêneos, você vai querer escrever a união à mão.
- Precisão numérica. O
numberdo JavaScript representa com segurança inteiros até 253−1. IDs inteiros maiores perdem precisão quando analisados porJSON.parse; se a sua API retorna inteiros de 64 bits, o padrão mais seguro é enviá-los como strings e tipá-los comostring.
Quando usar esta ferramenta
- Criar tipos a partir de uma resposta real de API. Acesse o endpoint, cole o JSON e obtenha um conjunto inicial de interfaces. Ajuste à mão para campos opcionais e literais de string.
- Adicionar tipos a um SDK de terceiros sem tipos. Muitas bibliotecas JS mais antigas vêm sem tipos. Gerar a partir de uma resposta de exemplo é mais rápido do que ler a documentação.
- Compartilhar tipos entre front-end e back-end. Gere a partir de um exemplo canônico e copie para as duas bases de código (ou compartilhe via um pacote de tipos publicado).
- Migrar uma base de código JS para TypeScript. Gere tipos a partir dos dados reais que passam pela aplicação e anote gradualmente as assinaturas das funções.
- Gerar tipos para um arquivo de configuração. A tipagem estrita torna os erros de configuração visíveis em tempo de compilação.
- Documentar o formato de um arquivo de dados interno. A interface gerada serve também como documentação legível por máquina.
Code-first vs. schema-first vs. direto (onde esta ferramenta se encaixa)
Três fluxos de trabalho comuns para obter tipos TypeScript a partir de dados em tempo de execução:
- Validadores de tempo de execução code-first: Zod, Yup, Effect Schema, Joi. Você escreve um schema validador em JS, e ele lhe dá tanto a análise em tempo de execução quanto um tipo TypeScript por inferência. O schema é a fonte da verdade. Melhor quando a validação importa tanto quanto o tipo.
- Schema-first: escreva uma especificação JSON Schema ou OpenAPI e gere tipos TypeScript com ferramentas como
quicktype,json-schema-to-typescriptouopenapi-typescript. Melhor quando um contrato de API abrange várias linguagens. - Inferência direta por amostra (esta ferramenta, mais o modo JSON puro do quicktype): cole dados reais e obtenha tipos. O caminho mais rápido; as garantias de validação mais fracas, porque nada verifica os dados em tempo de execução contra o tipo.
A escolha certa depende de se a sua preocupação é principalmente a verificação estática de tipos (esta ferramenta é ótima) ou também a segurança em tempo de execução (nesse caso, recorra ao Zod / Effect Schema).
Erros comuns
- Tratar os tipos gerados como uma especificação acabada. Eles são um ponto de partida 70% pronto. Adicione
?para campos opcionais,| nullonde for genuinamente anulável, e uniões de literais de string onde for aplicável. - Gerar a partir de um único exemplo quando a API tem variantes. Um objeto de usuário que às vezes tem um
emaile às vezes não vai gerar como «email obrigatório». Rode vários exemplos e una os resultados, ou edite à mão. - Marcar tudo como
readonlyautomaticamente. Útil para fluxos de dados imutáveis, mas errado para objetos de estado que você modifica. Use o botãoreadonlycom critério. - Confiar na precisão de IDs inteiros grandes. O
numberdo JavaScript chega ao máximo em 253−1. Para IDs de 64 bits, transmita como strings e tipe comostring. - Confundir
interfacecomtype. Ferramentas diferentes, compensações diferentes. A heurística do TypeScript Handbook é «use interface a menos que você precise de um recurso que só type oferece», exatamente o que esta ferramenta faz. - Colar JSON confidencial em um conversor do lado do servidor. Respostas reais de API costumam conter dados de clientes, credenciais e IDs internos. A conversão só no navegador (esta ferramenta) mantém os dados na sua máquina.
Mais perguntas frequentes
Por que todos os meus campos foram marcados como obrigatórios?
Porque um único exemplo de JSON não tem como dizer ao conversor quais campos às vezes estão ausentes na API real. Toda chave que aparece no exemplo vira obrigatória. Se você sabe que um campo é opcional, adicione um ? ao final à mão: email?: string;. Para a detecção de opcionalidade a partir de várias amostras, a CLI quicktype, mais sofisticada, lida com isso nativamente.
Por que o meu campo nulo está tipado como unknown?
Porque o conversor não tem como saber, a partir de um único null, se o campo é sempre anulável (string | null) ou se apenas calhou de ser null neste exemplo (string). unknown é o padrão conservador; o TypeScript vai obrigar você a estreitar o tipo antes de usar o valor, o que é mais seguro do que any. Edite para string | null à mão assim que souber a intenção da API.
Devo usar interface ou type?
A heurística do TypeScript Handbook oficial: use interface até precisar de um recurso que só type oferece, principalmente tipos de união, tipos de interseção ou nomear um primitivo. Este conversor segue essa regra: interface para todo formato de objeto, type para o alias do array raiz. Alguns guias de estilo recomendam usar type por padrão (Matt Pocock defendeu publicamente essa posição), mas o padrão convencional é interface para objetos.
O meu JSON será enviado para algum lugar?
Não. A conversão é uma IIFE de JavaScript autocontida que analisa o seu JSON via JSON.parse, percorre o valor e escreve a saída TypeScript em uma textarea. Não há fetch, nenhuma chamada de analytics carregando o conteúdo do JSON, nenhum servidor. Isso importa porque respostas reais de API normalmente contêm dados de clientes, IDs internos ou credenciais que você não quer que passem por terceiros.
E quanto a JSDoc, Zod ou validação em tempo de execução?
Esta ferramenta emite apenas tipos TypeScript de tempo de compilação: nenhum validador de tempo de execução (nada de Zod / Yup / Effect Schema), nenhum comentário JSDoc. Se você precisa de validação em tempo de execução que sirva também como tipo estático, escreva o schema em Zod e use o z.infer<typeof Schema> do Zod para derivar o tipo. Se você tem um JSON Schema e quer tanto a validação em tempo de execução quanto os tipos TS, json-schema-to-typescript + AJV é a combinação convencional.
Por que não há um prefixo I nos nomes das interfaces?
Porque a maioria dos guias de estilo modernos de TypeScript o abandona. O TypeScript Style Guide do Google recomenda explicitamente não usá-lo; a comunidade React convergiu para PascalCase sem prefixo. A convenção legada IUser veio da influência de C# / Java no início do TypeScript; a prática atual é simplesmente User.