Saltar al contenido

Lección 9 de 20 · Lectura y práctica

Tipar Respuestas de API con Genéricos y Utility Types

Concepto claveTipar respuestas de API con genéricos y utility types es una técnica avanzada que transforma el desarrollo frontend de arquitecturas complejas. En lugar de usar tipos estáticos o any, creas contratos de tipo.

Del concepto a la práctica

Taller de esta lección

Una respuesta genérica separa los datos del estado de transporte. Omit puede crear una vista pública sin un campo interno, pero no demuestra que un JSON externo sea válido.

Ejemplo resuelto

ts
type Api<T> = { data: T; status: number; receivedAt: string };
type Article = { id: string; title: string; internalNote: string };
type PublicArticle = Omit<Article, "internalNote">;
const response: Api<PublicArticle> = { data: { id: "a1", title: "Tipos" }, status: 200, receivedAt: "2026-01-10" };
console.log(response.data.title); // Tipos

Pruébalo

  1. Cambia Article por un recurso Task.

  2. Oculta internalNote con Omit.

  3. Añade una propiedad prohibida a data.

  4. Comprueba el error estructural.

Comprueba tu resultado

El objeto válido conserva id y title, y la salida es Tipos.

Error frecuente: escribir response.json() as Api<T> como si fuera validación. Corrígelo separando unknown, comprobaciones de forma y la conversión posterior al modelo seguro.

Omit no elimina campos de un objeto en ejecución. Si tienes un Article completo y lo asignas a una variable PublicArticle, internalNote puede seguir existiendo al serializar. Construye la vista con {id: article.id,title: article.title} y prueba JSON.stringify para confirmar que no se filtra. El rechazo de una propiedad adicional en un literal es una comprobación de TypeScript, distinta de la selección de datos. status200 por sí solo tampoco demuestra un cuerpo válido.

JSON externo pasa por unknown y validación en ejecución; Omit es estático y un objeto público debe construirse sin internalNote.
CursaloMapa de práctica
El tipo no valida el JSON

Un tipo o una afirmación as no valida un JSON externo. Comprueba su forma en ejecución antes de usarlo. Omit cambia la vista de tipos y no elimina campos del objeto: selecciona id y title al construir la respuesta pública y verifica su serialización.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

Concepto clave

Tipar respuestas de API con genéricos y utility types es una técnica avanzada que transforma el desarrollo frontend de arquitecturas complejas. En lugar de usar tipos estáticos o any, creas contratos de tipo flexibles que se adaptan dinámicamente a la estructura de datos devuelta por el backend. Esto es similar a cómo un arquitecto diseña planos modulares: defines un esqueleto genérico (el patrón de respuesta) y luego lo especializas para cada endpoint específico.

Los utility types como Partial, Pick, Omit y Record te permiten manipular tipos existentes sin duplicar código. Por ejemplo, Partial<T> hace todas las propiedades de T opcionales, útil para respuestas de API que pueden devolver datos incompletos en ciertos escenarios. Combinar esto con genéricos crea un sistema de tipos que escala con tu aplicación, reduciendo errores en tiempo de compilación y mejorando la autocompletación en tu IDE.

"Tipar APIs no es solo sobre validación; es sobre documentación viva que tu equipo puede usar para construir features más rápido y con menos bugs." — Experiencia de un Frontend Engineer en una startup de scale-up.

Cómo funciona en la práctica

Imagina que estás construyendo un dashboard de analytics con múltiples endpoints. Primero, defines un tipo base para respuestas de API:

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

Luego, usas utility types para adaptar tipos de dominio. Supón que tienes un tipo User:

interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user';
  createdAt: Date;
}

Para un endpoint que devuelve una lista de usuarios con solo id y name (por ejemplo, para un dropdown), usas Pick:

type UserListResponse = ApiResponse<Pick<User, 'id' | 'name'>[]>;

Para otro endpoint que actualiza un usuario y acepta propiedades parciales, usas Partial:

type UpdateUserRequest = Partial<Omit<User, 'id' | 'createdAt'>>;

Esto asegura que el frontend solo envíe campos modificables, evitando errores comunes como intentar cambiar un id.

Caso de estudio

En una aplicación de e-commerce con arquitectura microservicios, cada servicio (users, products, orders) devuelve respuestas similares pero con datos distintos. Usamos genéricos para crear un cliente de API reutilizable:

async function fetchApi<T>(endpoint: string): Promise<ApiResponse<T>> {
  const response = await fetch(`https://api.example.com/${endpoint}`);
  const data: ApiResponse<T> = await response.json();
  return data;
}

Luego, tipamos respuestas específicas. Para el servicio de productos:

interface Product {
  id: string;
  name: string;
  price: number;
  category: string;
  inStock: boolean;
}

type ProductsResponse = ApiResponse<Product[]>;

// Uso en componente
const getProducts = async (): Promise<ProductsResponse> => {
  return fetchApi<Product[]>('products');
};

Para un endpoint de búsqueda que devuelve productos con campos opcionales, usamos Partial en el tipo de respuesta, reflejando que algunos campos pueden faltar en resultados parciales.

Errores comunes

  • Usar any en respuestas de API: Pierdes todos los beneficios de TypeScript. En su lugar, define tipos mínimos con unknown y haz type guards.
  • Duplicar tipos para endpoints similares: Crea tipos base y usa utility types para variaciones, evitando inconsistencia.
  • Ignorar estados de error en el tipado: Tipa tanto respuestas exitosas como errores, por ejemplo, con un tipo union ApiResponse<T> | ApiError.
  • No alinear tipos frontend-backend: Usa herramientas como OpenAPI o protobufs para generar tipos automáticamente desde contratos de API.
  • Olvidar tipar respuestas anidadas: Para datos complejos (ej., usuario con órdenes), usa tipos recursivos o Record para mapeos.

Checklist de dominio

  1. ¿Puedes definir un tipo genérico ApiResponse<T> que cubra data, status y message?
  2. ¿Sabes usar al menos tres utility types (Partial, Pick, Omit) en respuestas de API?
  3. ¿Has implementado un cliente de API con genéricos que se reutilice en múltiples endpoints?
  4. ¿Puedes tipar respuestas con datos anidados (ej., listas de objetos con relaciones)?
  5. ¿Entiendes cómo evitar la duplicación de tipos entre frontend y backend?
  6. ¿Has manejado errores de API con tipos específicos (no solo catch genérico)?
  7. ¿Puedes explicar la diferencia entre Record<string, T> y un array para respuestas de diccionario?

Construye un cliente de API tipado para un sistema de blog

En este ejercicio, crearás un cliente de API tipado para un sistema de blog con posts y comentarios. Sigue estos pasos:

  1. Define los tipos de dominio: Post con id, title, content, authorId, y Comment con id, text, postId.
  2. Crea un tipo genérico ApiResponse<T> que incluya data (de tipo T), status (number), y timestamp (string).
  3. Implementa una función fetchBlogApi<T>(endpoint: string) que devuelva una Promise<ApiResponse<T>>, simulando una llamada API con setTimeout y datos mock.
  4. Tipa respuestas específicas:
    • Para /posts, devuelve un array de Post.
    • Para /posts/:id, devuelve un Post con sus comentarios anidados (usa un tipo combinado).
    • Para /comments, devuelve solo id y text usando Pick.
  5. Escribe un ejemplo de uso que llame a estos endpoints y maneje los tipos correctamente.
Pistas
  • Usa Partial para simular datos incompletos en respuestas de edición.
  • Considera usar Record<string, Comment[]> para mapear comentarios por postId.
  • Asegúrate de que tu función fetchBlogApi use genéricos para inferir el tipo de data.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con TypeScript Avanzado: Patrones Genéricos y Tipado Profundo para Arquitecturas Complejas

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.