Saltar al contenido principal

Convertir JSON a TypeScript

JSON a TypeScript genera interfaces a partir de un documento de ejemplo, en tu navegador. Pega todos los registros que tengas en lugar de uno: un campo que aparece en algunos registros y en otros no solo es detectable comparando ejemplos, y así se convierte en un miembro opcional y no en uno obligatorio que falta en tiempo de ejecución.

Solo local
Forma
JSON de ejemplo
0 B1 líneaLín. 1, Col. 1
Error de sintaxis · Error en la línea 1, columna 1

El documento termina antes de tiempo; parece incompleto.


^
Código generadosolo lectura
0 B1 línea
Si tienes varios registros, pega más de uno. Así se detectan campos opcionales que no aparecen en todas las filas.

¿Cómo funciona Convertir JSON a TypeScript?

El generador construye un modelo de tipos intermedio a partir de tu ejemplo y luego lo renderiza, lo que suena a detalle de implementación y es la razón de que la salida sea correcta. Las decisiones de verdad difíciles — si este campo es opcional, si estos dos objetos son del mismo tipo, cuál es el tipo de elemento de un array mixto — se responden una vez, en un solo lugar, en vez de volver a deducirse cada vez que aparece un valor.

Los campos opcionales salen de las discrepancias entre registros

Dado [{"a":1}, {"a":1,"b":2}], la implementación obvia lee el primer elemento y produce { a: number }, perdiendo b en silencio. La respuesta correcta fusiona los conjuntos de campos de todos los elementos: a está en ambos, así que es obligatorio; b está en uno, así que es b?: number. Esta es la mayor diferencia entre generadores, y es la razón de que pegar un solo registro produzca un tipo que describe un registro y no tu API.

Las formas idénticas se convierten en un tipo, no en cincuenta

Cada objeto se identifica por su estructura — nombres de claves, opcionalidad y la huella de cada tipo de valor, sin depender del orden. Un documento con cincuenta clientes, cada uno con una dirección de la misma forma, produce una sola interfaz Address en lugar de Address hasta Address50. Los nombres salen de la clave que contenía el objeto, en singular cuando contenía un array, así que "users": [{…}] genera User.

null es nulidad, no un tipo

Cuando un campo es un número en un registro y null en otro, la salida es number | null en lugar de un tipo unión con un nombre generado. Cuando un campo es null en todos los registros, la respuesta honesta es unknown con un comentario que lo diga — emitir null sería exacto respecto a tu ejemplo e inútil respecto a tus datos.

Los números son number, con una nota

TypeScript tiene un único tipo numérico, así que enteros y flotantes se convierten ambos en number. Un entero demasiado grande para un tipo de 32 bits igualmente se marca en un comentario, porque el mismo modelo alimenta a los generadores de Go, Java y C#, donde esa distinción decide entre int e int64 — y porque que un ID de 64 bits llegue a JavaScript ya es algo que conviene saber.

Ejemplo

[
  { "id": 1, "name": "Ada", "deleted_at": null },
  { "id": 2, "name": "Grace", "deleted_at": null, "team": "ops" }
]

Generado

export interface User {
  id: number;
  name: string;
  deleted_at: unknown; // only null in the sample
  team?: string;
}

¿Qué opciones y casos límite admite Convertir JSON a TypeScript?

Referencia técnica y opciones
ParámetroTipoValor predeterminadoComportamiento y casos límite
Tipo raízidentificadorRootNombre para el tipo de nivel superior. Una raíz de array se reporta como Nombre[], y las formas de objeto dentro de ella se nombran según las claves que las contienen.
interface / typedeclaracióninterfaceLas interfaces admiten fusión de declaraciones y producen mejores mensajes de error en formas de objeto; los alias de tipo son necesarios si luego quieres uniones o tipos mapeados. Ambos son válidos aquí.
readonlybooleanooffMarca todos los miembros como readonly. Vale la pena activarlo para una respuesta de API parseada, que nada en tu código debería mutar en su lugar.
claves camelCasebooleanooffRenombra claves en snake_case y registra la original en un comentario al final. Solo es correcto si algo en tu pipeline realmente las renombra; de lo contrario, el tipo generado deja de coincidir con el JSON.
Opcionalidadinferidosegún todos los registrosUna clave ausente en al menos un registro de la misma forma se vuelve opcional. Pega varios registros; un registro no puede expresar esto.
Anulableinferidounión con nullUn valor que es null en algunos registros y string en otros se convierte en string | null. Ausente y null son cosas diferentes y se reportan de forma distinta.
Arrays mixtosuniónentre paréntesisUn array de escalares mixtos se convierte en (string | number)[]. Los paréntesis son importantes: string | number[] significa algo completamente distinto.
Tamaño de entradabytes2 MBLa inferencia lee cada valor. unos pocos cientos de registros representativos describen una forma tan bien como un millón, así que el límite prácticamente no tiene coste.

Preguntas frecuentes

¿Por qué un campo es opcional si mi API siempre lo envía?

Porque al menos un registro del ejemplo que pegaste no lo tenía. El generador solo puede describir los datos que se le dieron. Si el campo de verdad está siempre presente, pega un ejemplo donde aparezca siempre — o quita el ? a mano, que es la decisión correcta cuando conoces el contrato mejor que el ejemplo.

¿Debería pegar un registro o la respuesta entera?

La respuesta entera, y a ser posible varias. La opcionalidad, la nulidad y los tipos mezclados son propiedades del conjunto de registros, no de uno solo. Un generador al que le das un registro no puede distinguir un campo que siempre está presente de uno que resultó estar presente esa vez, y con total confianza producirá un tipo equivocado de la manera más difícil de notar.

¿Por qué obtuve unknown en lugar de un tipo real?

Todos los ejemplos en esa posición eran null, así que no hay nada de donde inferir. Las alternativas son peores: null como tipo es exacto respecto al ejemplo e inútil respecto a los datos, y any desactiva la comprobación de tipos para todo lo que va después. unknown te obliga a acotarlo antes de usarlo, que es el resultado correcto cuando el tipo es genuinamente desconocido.

¿Puede generar validadores de tiempo de ejecución, no solo tipos?

No. Los tipos de TypeScript se borran al compilar, así que una interfaz generada a partir de un ejemplo no te dice nada sobre la respuesta que realmente recibiste en tiempo de ejecución. Si necesitas la garantía y no la anotación, genera mejor un JSON Schema y valida contra él, o escribe a mano un esquema de Zod. Tratar una interfaz generada como validación es un error común y caro.

¿Maneja documentos profundamente anidados o recursivos?

El anidamiento, sí, hasta una profundidad de 100 — más allá el código generado sería inutilizable de todos modos, así que hay un límite claro en lugar de un desbordamiento de pila. La recursividad verdadera (un comentario que contiene comentarios) se infiere hasta donde llega el ejemplo; si el ejemplo tiene tres niveles, obtienes tres niveles, porque nada en los datos dice que la estructura se repita para siempre.

¿Se sube mi JSON?

No. La inferencia y el renderizado se ejecutan ambos en la pestaña que ya tienes abierta — abre DevTools y observa el panel Network mientras pegas. Esto importa aquí más que en la mayoría de las herramientas, porque los documentos que la gente convierte son respuestas de API en producción, a menudo con registros reales de clientes dentro.