Manejo de errores en TypeScript: técnicas avanzadas de try/catch

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Manejo avanzado de errores en TypeScript: de try/catch a soluciones tiposeguras



El manejo de errores es un aspecto crítico del desarrollo en TypeScript. El try/catch básico a menudo resulta insuficiente para aplicaciones complejas. En este artículo exploraremos técnicas avanzadas que ayudarán a que tu código sea más robusto, predecible y tiposeguro.



1. El problema del try/catch estándar: pérdida de tipos



La principal desventaja del catch clásico es que la variable de error tiene el tipo unknown (o any en versiones antiguas). Esto obliga al desarrollador a verificar manualmente el tipo:



try {  riskyOperation();} catch (error) {  // error: unknown  if (error instanceof Error) {    console.error(error.message);  } else {    console.error('Error desconocido', error);  }}


Solución: crear una utilidad para la captura tipificada de errores:



function getErrorMessage(error: unknown): string {  if (error instanceof Error) return error.message;  if (typeof error === 'string') return error;  if (error && typeof error === 'object' && 'message' in error) {    return String((error as { message: unknown }).message);  }  return 'Ocurrió un error desconocido';}

try { riskyOperation();} catch (error) { console.error(getErrorMessage(error));}


2. Clases de error personalizadas con datos tipificados



Crear una jerarquía de errores permite identificar con precisión el problema y transmitir datos adicionales:



// Clase baseclass AppError extends Error {  constructor(    message: string,    public readonly code: number,    public readonly isOperational: boolean = true  ) {    super(message);    this.name = 'AppError';  }}

// Errores especializadosclass ValidationError extends AppError { constructor( message: string, public readonly field: string, public readonly invalidValue: unknown ) { super(message, 400); this.name = 'ValidationError'; }}

class NotFoundError extends AppError { constructor(entity: string, id: string) { super(`${entity} con ID ${id} no encontrado`, 404, false); this.name = 'NotFoundError'; }}

// Usofunction findUser(id: string): User { if (!validateId(id)) { throw new ValidationError('ID inválido', 'id', id); } const user = db.findUser(id); if (!user) { throw new NotFoundError('Usuario', id); } return user;}

try { const user = findUser('123');} catch (error) { if (error instanceof NotFoundError) { // error.code === 404, error.message contiene la descripción console.warn(error.message); } else if (error instanceof ValidationError) { // error.field y error.invalidValue están disponibles console.error(`Error en el campo ${error.field}: ${error.message}`); } else if (error instanceof AppError) { console.error(`Error de aplicación (código ${error.code}): ${error.message}`); }}


3. Uniones discriminadas para el manejo de errores



Este patrón permite manejar los resultados de las operaciones sin excepciones, utilizando una unión de tipos con discriminante:



// Tipo de resultado con discriminantetype Result<T, E = Error> =   | { success: true; data: T }  | { success: false; error: E };

// Función que devuelve un Resultfunction safeDivide(a: number, b: number): Result<number, string> { if (b === 0) { return { success: false, error: 'División por cero' }; } return { success: true, data: a / b };}

// Usoconst result = safeDivide(10, 0);

if (result.success) { // TypeScript sabe que result.data es number console.log(`Resultado: ${result.data}`);} else { // result.error es string console.error(`Error: ${result.error}`);}

// Ejemplo más complejo con errores personalizadostype UserResult = Result<

Blogs

Book Recommendations