Escrever tipos TypeScript a mao para uma resposta JSON que voce ja tem e repetitivo e facil de fazer sutilmente errado na primeira tentativa, especialmente quando um campo e opcional ou um valor e aninhado tres niveis de profundidade.
Usando o gerador JSON para TypeScript
Cole um documento, ou varios registros em um array, nomeie o tipo raiz, escolha interfaces ou type aliases, e pressione Gerar tipos. A inferencia de tipo e compartilhada com o gerador de schema neste site, entao as duas paginas concordam sobre o que seu documento realmente contem e so diferem em como escrevem a resposta.
Dado
[
{"user": {"name": "a"}, "tags": [], "meta": {}},
{"user": {"name": "b"}, "tags": ["x"], "meta": {}, "extra": true}
]
a saida e:
export interface RootItem {
user: User
tags: string[]
meta: Record<string, unknown>
extra?: boolean
}
export interface User {
name: string
}
export type Root = RootItem[]
Por que objetos aninhados recebem seu proprio tipo nomeado
Um tipo inline tres niveis de profundidade e ilegivel, e nada mais no
arquivo pode se referir a ele. Os nomes vem da chave que contem o objeto,
singularizada dentro de um array (RootItem de Root), e um nome repetido
ganha um numero anexado para que a saida sempre compile sem uma colisao.
O que a marca opcional realmente promete
extra?: boolean significa que a chave faltava em pelo menos um registro
na sua amostra, exatamente a mesma regra que o gerador de schema usa para
required. Nao significa que o campo e garantidamente opcional em toda
sua API, apenas que sua amostra nao pode provar que ele sempre esta
presente. Leia a marca como evidencia dos seus dados, nao como uma
garantia do sistema de origem.
Valores vazios
Um objeto vazio se torna Record<string, unknown> em vez de uma interface
vazia, pois uma interface vazia aceita qualquer coisa e nao diz nada util
sobre a forma. Um array vazio se torna unknown[], porque nao ha nada
dentro para inferir um tipo de elemento, e inventar um seria um palpito
disfarçado de fato.
Por que todo numero e apenas number
TypeScript nao tem um tipo inteiro separado, entao um campo que sempre
e um numero inteiro na sua amostra ainda e digitado como number, igual
a um que contem decimais. Isso espelha como o proprio TypeScript modela
numeros, entao os tipos gerados compilam e se comportam exatamente como
tipos escritos a mao.