Una muestra JSON revela las formas y valores primitivos que aparecieron en una respuesta. No demuestra el contrato completo de una API. Convertirla a TypeScript sigue siendo útil: evita transcripción repetitiva y hace visible la incertidumbre mediante uniones, propiedades opcionales y unknown[].
Esta guía entrega dos registros sintéticos a la herramienta JSON a TypeScript. Incluye null, una propiedad ausente, un objeto anidado con miembro opcional, números y matrices vacías. El resultado se trata como borrador compilable, no como validador.
Declarar qué puede probar la muestra
Si dos objetos contienen una propiedad con tipos distintos, el generador forma una unión. Si falta en uno, la marca opcional. Si aparece null, lo conserva. Esas conclusiones proceden de los valores entregados.
Que una propiedad no aparezca no prueba que jamás exista; que aparezca siempre tampoco prueba que sea obligatoria. Una matriz vacía no aporta elementos para inferir y se expresa como unknown[], más honesto que any[] o un tipo inventado. La declaración ayuda al compilador, pero no inspecciona futuras respuestas en ejecución.
Muestra que expone incertidumbre
Usa exactamente:
[
{
"id": 1,
"tag": "alpha",
"active": true,
"notes": [],
"meta": { "source": "api" }
},
{
"id": 2,
"tag": null,
"notes": [],
"meta": { "source": "cache", "age": 3 }
}
]
Elige raíz ApiResponse y type. La raíz es una matriz de objetos fusionados. id es number; tag, null | string; active es opcional porque falta en el segundo; notes es unknown[]; y meta.age es opcional. La salida es determinista y compilable; el espaciado no forma parte de la prueba semántica.
Generar, compilar y desafiar
Pega la muestra, escribe ApiResponse, elige type y genera. Copia a un .ts con modo estricto. Añade valores que coincidan con ambos registros y ejecuta el compilador: no debe haber diagnósticos.
Añade luego un error deliberado, por ejemplo id como cadena. El compilador debe rechazarlo. Esto demuestra comprobación estática, no validación HTTP. Para datos de red, analiza y pasa unknown por un esquema o guard antes de tratarlo como ApiResponse.
Repite con interface. Los objetos pueden emitirse como interfaces, pero una raíz matriz o primitiva necesita alias porque una interfaz no aliasa cualquier tipo. Compara significado, no que cada línea use la palabra elegida. Descarga y compila el archivo exacto que integrarás.
Cómo se fusiona la evidencia
El generador recorre todos los objetos de una matriz, no solo el primero. Une propiedades, marca ausencias con ? y combina tipos observados en un orden estable. Los objetos permanecen anidados. Las matrices examinan sus elementos; si son heterogéneos crean uniones, y si están vacías producen unknown[].
Todos los números JSON son number: la muestra no establece entero, precisión o rango. Las cadenas siguen como string; no se inventan fechas, enums, marcas de URL ni literales. null explícito es distinto de una propiedad ausente. Con strictNullChecks, el consumidor debe manejar la unión.
Las claves que no son identificadores se entrecomillan. El nombre raíz sí debe ser identificador TypeScript válido. Las propiedades se ordenan de forma determinista, de modo que un cambio de salida corresponda a evidencia nueva y no al recorrido accidental.
Resolver errores de entrada
Corrige JSON inválido en el origen: comas finales, claves sin comillas, corchetes o prefijos de log. La guía de errores JSON ofrece un proceso específico. No generes tipos desde un literal JavaScript hasta convertirlo en JSON válido.
Un nombre raíz inválido contiene espacios, puntuación, empieza por dígito o no puede ser identificador. Usa ApiResponse, no una URL. Las claves internas pueden ser arbitrarias porque se citan.
Más de 200 KiB UTF-8 o profundidad superior a 50 se rechazan. Reduce a registros sintéticos representativos sin borrar cierres al azar. Un payload profundamente recursivo necesita un modelo diseñado, no un tipo inline gigantesco.
Convertir el borrador en contrato mantenido
Compara con el esquema oficial y respuestas de éxito, vacío, permisos parciales, legado y error. Ajusta opcionalidad y uniones según comportamiento documentado. Nombra conceptos anidados reutilizables y comenta la versión del contrato, no solo la fecha de muestra.
Combina tipos estáticos con validación en la frontera. Los tipos se borran al ejecutar JavaScript. Una aserción silencia al compilador sin comprobar bytes. Analiza JSON, valida unknown y solo después expón el valor al código tipado.
No pegues respuestas reales de clientes. Aunque el cálculo sea local, fixture, descarga, commit o captura pueden divulgar datos. Minimiza y sustituye identificadores. La guía de privacidad cubre el manejo general.
Límites de inferir desde muestras
La herramienta solo ve el JSON aportado. No descubre variantes ausentes, requisitos condicionales, rangos, formatos semánticos ni cambios futuros. No llama a la red, lee OpenAPI, valida en ejecución, genera codecs ni garantiza representatividad.
Una unión inferida tampoco identifica por sí sola un discriminante. Si el contrato ofrece un campo kind, revisa que cada variante tenga sus propiedades correctas y modela una unión discriminada conscientemente. Si dos objetos solo coinciden por casualidad, fusionarlos puede producir un tipo demasiado permisivo. La herramienta resume evidencia; la persona responsable decide el dominio.
Las propiedades opcionales merecen una revisión especial con exactOptionalPropertyTypes. Faltar y estar presente con undefined no son idénticos en todos los proyectos, mientras que JSON ni siquiera puede representar undefined. Comprueba las opciones reales de tsconfig y no añadas undefined explícito sin una razón documentada.
Números son number; cadenas no son fechas ni enums; vacíos son unknown[]; matrices heterogéneas usan uniones; y una propiedad es opcional solo cuando el conjunto demuestra ausencia. Límite: 200 KiB y profundidad 50. Trata la salida como borrador revisable.
Lista final de TypeScript
Usa JSON válido y sintético con nombre raíz válido. Incluye varios objetos cuando importen opcionales o uniones. Revisa cada ?, null, unión, objeto y unknown[]. Elige interfaz o tipo según el proyecto, aceptando alias si la raíz no es objeto.
Compila el archivo descargado con opciones estrictas. Añade una asignación válida y una inválida. Compara con la documentación, valida datos no confiables en ejecución y registra los casos de muestra. Al cambiar el contrato, regenera y revisa el diff en vez de sustituir ciegamente.
Amplía la muestra con un caso vacío y otro parcialmente poblado si ambos son válidos en la API. Confirma que la matriz vacía sigue como unknown[] hasta disponer de evidencia o esquema. Prueba claves con guiones para revisar su entrecomillado y una raíz primitiva para comprobar el alias. Ejecuta el compilador en CI con la misma configuración que la aplicación.
Por último, conserva separado el fixture sintético del payload real. Anota qué campos fueron sustituidos y qué escenarios cubre, sin copiar datos personales. Cuando una versión nueva de la API cambie el ejemplo, actualiza contrato, validador de ejecución y tipos en una sola revisión para que ninguno quede dando una garantía antigua.
Revisa también los consumidores: un campo opcional obliga a decidir un valor alternativo o una rama, y una unión con null exige tratamiento explícito. Evita resolver ambos con ! o conversiones indiscriminadas. Añade pruebas para cada rama observada y para el rechazo de un valor desconocido. Así el tipo generado se convierte en una lista concreta de decisiones pendientes, en vez de una declaración decorativa que compila pero no protege la frontera.
Prueba también una clave con guion y una raíz primitiva. La primera debe aparecer entrecomillada; la segunda necesita alias aunque selecciones interfaz. Estos casos verifican que la salida siga siendo TypeScript válido fuera del ejemplo principal.
Fuentes: TypeScript Handbook: Object Types, TypeScript Handbook: Unions y RFC 8259: JSON.