Escribir tipos TypeScript a mano para una respuesta JSON que ya tienes es repetitivo y facil de hacer sutilmente mal en el primer intento, especialmente cuando un campo es opcional o un valor esta anidado tres niveles de profundidad.
Usando el generador JSON a TypeScript
Pega un documento, o varios registros en un array, nombra el tipo raiz, elige interfaces o type aliases, y presiona Generar tipos. La inferencia de tipos se comparte con el generador de schema en este sitio, por lo que las dos paginas coinciden sobre lo que tu documento realmente contiene y solo difieren en como escriben la respuesta.
Dado
[
{"user": {"name": "a"}, "tags": [], "meta": {}},
{"user": {"name": "b"}, "tags": ["x"], "meta": {}, "extra": true}
]
la salida es:
export interface RootItem {
user: User
tags: string[]
meta: Record<string, unknown>
extra?: boolean
}
export interface User {
name: string
}
export type Root = RootItem[]
Por que los objetos anidados obtienen su propio tipo nombrado
Un tipo en linea tres niveles de profundidad es ilegible, y nada mas en el
archivo puede referirse a el. Los nombres vienen de la clave que contiene
el objeto, singularizada dentro de un array (RootItem de Root), y un
nombre repetido obtiene un numero adjunto para que la salida siempre compile
sin una colision.
Que promete realmente la marca opcional
extra?: boolean significa que la clave faltaba en al menos un registro en
tu muestra, exactamente la misma regla que el generador de schema usa para
required. No significa que el campo sea garantizado opcional en toda tu
API, solo que tu muestra no puede probar que siempre esta presente. Lee
la marca como evidencia de tus datos, no como una garantia del sistema
fuente.
Valores vacios
Un objeto vacio se convierte en Record<string, unknown> en vez de una
interface vacia, ya que una interface vacia acepta cualquier cosa y no dice
nada util sobre la forma. Un array vacio se convierte en unknown[], porque
no hay nada dentro del cual inferir un tipo de elemento, e inventar uno
seria una suposicion disfrazada de hecho.
Por que todo numero es solo number
TypeScript no tiene un tipo entero separado, asi que un campo que siempre
es un numero entero en tu muestra aun se escribe como number, igual que
uno que contiene decimales. Eso refleja como TypeScript modela los numeros
por si mismo, por lo que los tipos generados compilan y se comportan
exactamente como los escritos a mano.