JSON a TypeScript
Interfaces fusionadas a partir de todos los elementos del array, para que lo opcional sea realmente opcional.
Nada de lo que pegues sale de tu navegador. La lista de permitidos de connect-src convierte eso en una garantía del navegador, no en una promesa. Compruébalo tú mismo
Convierte un payload JSON en interfaces de TypeScript. Los objetos anidados pasan a ser tipos con nombre propio, los arrays se fusionan a lo largo de todos sus elementos, y las formas estructuralmente idénticas se emiten una vez y se reutilizan.
Inferir a partir de una muestra es adivinar. Lo que aporta esta página es que las suposiciones quedan a la vista.
Campos opcionales, que es donde falla la mayoría de generadores
Un generador que lee el elemento cero de un array y se detiene produce una interfaz donde todos los campos son obligatorios. El primer registro que omita un campo opcional falla la comprobación de tipos, y acabas editando a mano los tipos generados, lo cual anula el propósito.
Este fusiona todos los elementos. Una clave presente en todos es obligatoria; una clave presente en algunos se marca como opcional con un signo de interrogación. Eso es información real, extraída de tu muestra, que un generador de un solo elemento tira a la basura.
Las demás decisiones
- null pasa a ser una unión
- Un campo visto como cadena y como null es string | null, no any y no string.
- Un array vacío es unknown[]
- No any[]. Un array vacío no aporta información de tipos, y any[] apagaría en silencio la comprobación para todo lo que lo toque.
- Las formas repetidas se deduplican
- Una lista de quinientos registros produce una interfaz, no quinientas.
- Los nombres de elemento de array se ponen en singular
- Un array categories produce una interfaz Category.
- Los identificadores no válidos se entrecomillan
- Una clave has-dash, 2fast o class pasa a ser un nombre de propiedad entrecomillado.
- Los enteros inseguros se señalan
- Un campo tipado como number cuando la muestra contenía un entero por encima de 2^53-1 es una mentira, porque JavaScript no puede representarlo. La nota lo dice; el arreglo correcto está aguas arriba, enviándolo como cadena.
Lo que un tipo generado no te da
Una interfaz de TypeScript se borra en tiempo de ejecución. Le dice al compilador qué esperas y no hace absolutamente nada cuando la API envía otra cosa. Para eso necesitas un validador en tiempo de ejecución, y el flujo honesto para una API externa es un esquema que valida e infiere el tipo desde la misma definición.
Zod, Valibot y ArkType hacen esto. Genera aquí una interfaz para entender un payload, y luego escribe el esquema en tiempo de ejecución para la frontera que no controlas.
How to do this in code
La misma idea en código, y qué usar en una frontera de la que no te fías.
sh quicktype
quicktype admite muchos lenguajes de destino. Pasar varias muestras es la opción que de verdad importa.
npx quicktype --lang ts --just-types --src-lang json payload.json
# Several samples, which is what makes optionality accurate
npx quicktype --lang ts --just-types samples/*.json ts Zod
Este es el patrón al que recurrir en la frontera de una API. La interfaz se lo cuenta al compilador; el esquema dice la verdad.
import { z } from 'zod';
const User = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
verifiedAt: z.string().nullable(),
roles: z.array(z.string()),
});
// One definition, both a runtime check and a static type
type User = z.infer<typeof User>;
const result = User.safeParse(await res.json());
if (!result.success) console.error(result.error.issues); ts Solo tipos, a partir de un literal
// If the data is a constant you control, TypeScript can infer
// the type without a generator at all.
const config = {
retries: 3,
endpoints: ['a', 'b'],
} as const;
type Config = typeof config; Preguntas frecuentes
- ¿Por qué un campo sale opcional si mi API siempre lo envía?
- Porque al menos un registro de la muestra no lo tenía. Eso es o un campo opcional de verdad o una muestra incompleta. Pega un array con más registros y la respuesta mejora.
- ¿Debería usar interface o type?
- Para formas de objeto casi da igual. Las interfaces admiten fusión de declaraciones y producen mensajes de error algo mejores; los alias de tipo pueden expresar uniones y tipos mapeados. Arriba tienes ambos.
- ¿Estos tipos validan algo en tiempo de ejecución?
- No. Los tipos de TypeScript se borran al compilar. Describen lo que crees; no lo comprueban. Para datos que cruzan una frontera de red, usa un validador en tiempo de ejecución.