Fundamentos de TypeScript para desarrolladores de JavaScript: Dominando los Genéricos

Comprendiendo los Genéricos: Parámetros de Tipo

En JavaScript, pasamos datos como argumentos a funciones. En TypeScript, podemos pasar tipos como argumentos. A esto se le llama genérico (generic). Un genérico actúa como un contenedor de tipos flexible, a menudo representado con <T> (donde T denota un Tipo), permitiendo que una estructura de código se adapte a múltiples implementaciones de tipo con seguridad.

Aplicación Práctica en Funciones Utilitarias

Consideremos una función para recuperar datos del almacenamiento local del navegador. Sin genéricos, tendríamos que elegir entre tipos rígidos o el inseguro any.

Implementación con genéricos:

// Declaración de una función genérica
function recuperarDatoAlmacenado<T>(clave: string): T | null {
  const valorBruto = localStorage.getItem(clave);
  if (!valorBruto === null) return null;
  try {
    return JSON.parse(valorBruto) as T;
  } catch {
    return null;
  }
}

// Definición de tipos específicos para el negocio
interface DatosSesion {
  idSesion: string;
  caducidad: number;
}

interface PreferenciasUI {
  tema: 'claro' | 'oscuro';
  idioma: string;
}

// Uso: el tipo se infiere o se especifica explícitamente.
const sesionActual = recuperarDatoAlmacenado<DatosSesion>('sesion');
const temaActual = recuperarDatoAlmacenado<PreferenciasUI>('preferencias');

Arquitectura Clave: Modelado de Respuestas de API Genéricas

Las APIs web suelen devolver respuestas con un formato común que incluye metadatos (como código de estado y mensaje) y un cuerpo de datos (data) cuya estructura varía. Definir una interfaz genérica evita duplicar tipos para cada endpoint.

// Interfaz genérica base para todas las respuestas de la API
interface RespuestaAPI<TPayload> {
  codigoHttp: number;
  mensaje: string;
  datos: TPayload;
}

// Tipos de datos específicos del dominio
interface PerfilUsuario {
  uuid: string;
  nombreCompleto: string;
  email: string;
}

interface InstanciaServicio {
  nombreIntancia: string;
  region: string;
  estadoOperativo: 'en_linea' | 'mantenimiento';
  metrics: { cpu: number; ram: number };
}

// Funciones que consumen la API usando los tipos genéricos
async function obtenerPerfil(): Promise<RespuestaAPI<PerfilUsuario>> {
  const respuesta = await fetch('/api/perfil');
  return respuesta.json();
}

async function listarInstancias(): Promise<RespuestaAPI<InstanciaServicio[]>> {
  const respuesta = await fetch('/api/instancias');
  return respuesta.json();
}

La firma de tipo RespuestaAPI<InstanciaServicio[]> es elocuente por sí sola: comunica que la respuesta contendrá un array de objetos de tipo InstanciaServicio dentro del campo datos.

Extensión Avanzada: Genéricos Anidados para Pgainación

Para manejar respuestas paginadas, podemos anidar genéricos. Se crea una estructura genérica que garantiza que datos sea siempre una lista.

// Estructura genérica para respuestas paginadas
interface RespuestaPaginada<TElemento> {
  elementos: TElemento[];
  totalElementos: number;
  paginaActual: number;
  tamanoPagina: number;
}

// Modelo de negocio específico
interface ModeloInteligenciaArtificial {
  identificadorModelo: string;
  proveedor: string;
  ventanaContextoMax: number;
}

// Combina los genéricos: una respuesta de API que contiene una lista paginada
async function obtenerModelos(
  pagina: number
): Promise<RespuestaAPI<RespuestaPaginada<ModeloInteligenciaArtificial>>> {
  const res = await fetch(`/api/modelos?pagina=${pagina}`);
  return res.json();
}

Esta construcción anidada RespuestaAPI<RespuestaPaginada<...>> proporciona una descripción completa y segura del contrato de tipo, mejorando drásticamente la mantenibilidad y autodocumentación del código.

Etiquetas: TypeScript Genéricos frontend APIs REST Tipado Estático

Publicado el 7-7 05:28