
Deja de escribir interfaces TypeScript a mano: usa un generador JSON
📷 Roman Synkevych / PexelsDeja de escribir interfaces TypeScript a mano: usa un generador JSON
Escribir manualmente interfaces TypeScript desde payloads JSON es tedioso y propenso a errores. Aquí se explica cómo automatizarlo y qué tener en cuenta.
Si alguna vez has pasado veinte minutos escribiendo a mano interfaces TypeScript desde un payload JSON que acabas de recibir de una API, ya sabes que es una de esas tareas que parecen importantes pero son casi completamente mecánicas. No estás pensando. Solo estás copiando nombres de campos e infiriendo tipos. Es el tipo de trabajo que debería hacer una máquina.
Sin embargo, muchos desarrolladores todavía lo hacen a mano. Esta guía explica por qué vale la pena dejar de hacerlo, qué produce realmente un generador JSON a TypeScript, y — más importante — qué no puede hacer para que sepas dónde tomar el control.
Por qué las interfaces TypeScript realmente importan
Antes de entrar en la herramienta, vale la pena ser preciso sobre qué obtienes de las interfaces tipadas más allá de "detectar bugs".
El autocompletado del IDE es el más subestimado. Cuando tu respuesta de API está tipada, tu editor sabe exactamente qué campos existen y qué forma tienen los objetos anidados. Dejas de adivinar si es user.profilePicture o user.profile_picture o user.avatar.
El refactoring se vuelve mucho más seguro. Si un equipo de backend renombra un campo de userId a user_id, cada lugar en tu base de código que hace referencia al nombre antiguo falla en tiempo de compilación — no silenciosamente en tiempo de ejecución después de que un usuario encuentre un error.
Documentación que no se vuelve obsoleta. Una interfaz bien nombrada suele ser más útil que documentación escrita.
El proceso manual vs. usar un generador
Así es como se ve escribir tipos a mano para una respuesta de API de complejidad media:
{
"user": {
"id": 1042,
"email": "alice@example.com",
"name": "Alice Nguyen",
"roles": ["admin", "editor"],
"profile": {
"bio": "Frontend developer based in Berlin.",
"avatarUrl": "https://cdn.example.com/avatars/1042.png",
"joinedAt": "2023-06-15T08:30:00Z"
},
"settings": {
"theme": "dark",
"notifications": {
"email": true,
"push": false
}
}
},
"meta": {
"requestId": "abc-123",
"timestamp": 1712486400
}
}
Pega el mismo JSON en la herramienta JSON a TypeScript y obtienes esto en menos de un segundo:
export interface Root {
user: User;
meta: Meta;
}
export interface User {
id: number;
email: string;
name: string;
roles: string[];
profile: Profile;
settings: Settings;
}
export interface Profile {
bio: string;
avatarUrl: string;
joinedAt: string;
}
export interface Settings {
theme: string;
notifications: Notifications;
}
export interface Notifications {
email: boolean;
push: boolean;
}
export interface Meta {
requestId: string;
timestamp: number;
}
Todo lo que necesitas hacer es renombrar Root a algo significativo como UserResponse.
Casos de uso del mundo real
Tipado de respuestas de API
Este es el caso de uso principal. Estás integrando una API de terceros — procesador de pagos, CRM, servicio meteorológico — y necesitas tipos para lo que devuelve.
Archivos de configuración
Si tu aplicación lee un archivo de configuración JSON en tiempo de ejecución, quieres una interfaz TypeScript correspondiente:
// config.interface.ts (generada desde config.json)
export interface AppConfig {
database: Database;
redis: Redis;
featureFlags: FeatureFlags;
}
export interface Database {
host: string;
port: number;
name: string;
ssl: boolean;
}
Datos de mock para pruebas
Al escribir pruebas, a menudo necesitas objetos mock tipados. Genera la interfaz desde datos reales, luego crea tu mock tipado contra ella.
Manejando los casos difíciles
Valores null
JSON permite null como valor, y los generadores tipificarán esos campos como null. Pero en la práctica, un campo null suele significar que el campo es opcional:
interface User {
middleName: string | null;
}
Fechas
JSON no tiene tipo Date nativo. "2023-06-15T08:30:00Z" es un string en lo que respecta a JSON. Algunos equipos crean un alias de tipo:
type ISODateString = string;
Uniones discriminadas
A veces una API devuelve diferentes formas dependiendo de un campo type o status. Tendrás que escribir esos tipos tú mismo:
type ApiResult = SuccessResult | ErrorResult;
interface SuccessResult {
type: "success";
data: OrderData;
}
interface ErrorResult {
type: "error";
code: string;
message: string;
}
Mejores prácticas para los tipos que generas
Nombrar la interfaz raíz de forma significativa
El generador la llamará Root o algo genérico. Siempre renómbrala antes de hacer commit. UserProfileResponse, CheckoutSessionPayload, ProductListItem.
Mantener los tipos en archivos dedicados
src/
types/
api/
user.types.ts
order.types.ts
config.types.ts
Zod para validación en tiempo de ejecución
Los tipos TypeScript se borran en tiempo de ejecución — no te protegen de que una API devuelva datos inesperados. Si necesitas garantías en tiempo de ejecución, considera Zod:
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
email: z.string().email(),
name: z.string(),
});
type User = z.infer<typeof UserSchema>;
Lo que el generador no puede hacer por ti
No conoce tu lógica de negocio. Un campo tipado como number podría en la práctica ser siempre un entero positivo.
Trabaja desde una instantánea. Los tipos generados reflejan una muestra de datos. Las APIs reales evolucionan.
No puede distinguir requerido de opcional. Cada campo en la muestra se trata como requerido.
Trata todas las cadenas como cadenas. Un campo status que solo contiene "pending", "active" o "cancelled" se tipificará como string en lugar del tipo unión literal más preciso.
Estas no son razones para evitar la herramienta — son razones para tratar la salida como un borrador, no como un producto terminado. El generador maneja el 80% del trabajo tedioso. Tú manejas el 20% que requiere comprender la semántica real de los datos.
Poniéndolo todo junto
El flujo de trabajo que tiene sentido para la mayoría de los proyectos:
- Obtener una muestra real (o representativa) del JSON desde la API, configuración u otra fuente
- Pegar en el generador JSON a TypeScript
- Renombrar
Roota algo significativo - Copiar la salida al archivo
*.types.tsapropiado - Revisar cada campo: marcar campos opcionales con
?, agregar| nulldonde sea necesario, convertir cadenas literales a tipos unión donde sea apropiado - Si tu JSON fuente está minificado y difícil de leer, usa el formateador JSON primero, luego genera tipos
- Si también mantienes una configuración YAML, el convertidor JSON a YAML puede ayudar a mantenerlos sincronizados
El objetivo es tener tipos TypeScript precisos, nombrados y organizados sin gastar tiempo en transcripción puramente mecánica. El generador hace la parte mecánica. Tú aportas el contexto sobre lo que los datos realmente significan.
Los tipos escritos a mano no son intrínsecamente mejores — son simplemente más lentos y más propensos a errores tipográficos. Usa la herramienta, revisa la salida y gasta tu tiempo en las partes que realmente requieren un humano.