Errores Personalizados en JavaScript
JavaScript permite crear tipos de error propios extendiendo la clase Error integrada, lo que habilita un manejo de errores más detallado y preciso.
Errores Personalizados en JavaScript
JavaScript te permite crear tus propios tipos de error extendiendo la clase Error integrada. Un error personalizado es simplemente una clase que hereda de Error (u otro tipo de error) y lleva un name significativo más cualquier dato adicional que la situación requiera.
Esta página explica por qué querrías usar errores personalizados, cómo definirlos correctamente, cómo distinguir tipos de error con instanceof, cómo adjuntar contexto (códigos de estado, nombres de campo, el cause original) y cómo organizar una jerarquía de errores para una aplicación real.
¿Por qué crear errores personalizados?
Lanzar un simple new Error("...") funciona, pero solo le entrega al código que lo llama un string para inspeccionar. Los errores personalizados resuelven tres problemas:
- Manejo basado en tipos. Con
instanceof ValidationErrorpuedes reaccionar ante un tipo concreto de fallo sin analizar el texto del mensaje, lo cual es frágil y depende del idioma. - Contexto adicional. Una clase personalizada puede llevar campos estructurados — un
statusCodeHTTP, elfieldinfractor, una sugerencia de reintento — en lugar de comprimir todo en el mensaje. - Jerarquías claras. Una clase base compartida (por ejemplo
AppError) permite que un manejador de nivel superior capture todos los errores de tu aplicación con un únicoinstanceof, mientras el código interno puede lanzar subtipos específicos.
Si solo necesitas aprender primero la mecánica de lanzar y capturar, lee Manejo de errores: try...catch. Los errores personalizados se construyen directamente sobre la herencia de clases y la extensión de clases integradas.
Bases para Extender la Clase Error
Para crear un error personalizado, usas extend en la clase Error. La nueva clase hereda message, stack y toString() de Error, y tú agregas lo que necesites.
Crear una Clase de Error Personalizada
Este es el patrón mínimo:
class ValidationError extends Error {
constructor(message) {
super(message); // Pass the message to the Error constructor (sets this.message)
this.name = "ValidationError"; // Override the default name "Error"
}
}Dos detalles importan:
super(message)debe ir primero. Dentro del constructor de una subclase no puedes usarthisantes de llamar asuper(). El constructor deErrorestablecethis.messagey captura el stack trace.- Establece
this.name. Sin él, el error se reporta como"Error"en los mensajes y entoString(). Establecernamehace que los registros y el patrónswitch (error.name)sean legibles.
También puedes ver Object.setPrototypeOf(this, new.target.prototype) en algunos ejemplos. Con transpiladores modernos y clases nativas generalmente no es necesario, pero no hace daño y garantiza que instanceof funcione incluso cuando el código se compila a ES5 o se comparte entre entornos (iframes o límites de workers). Los ejemplos a continuación lo conservan por seguridad.
Una vez creado, el error se comporta como cualquier otro:
const e = new ValidationError("bad input");
e.name; // "ValidationError"
e instanceof Error; // true — it is still a real Error
e.toString(); // "ValidationError: bad input"Usar Errores Personalizados
Una vez que has definido un error personalizado, puedes lanzarlo en tu aplicación como cualquier error estándar:
En este ejemplo, se valida un correo electrónico contra una expresión regular. Si la validación falla, se lanza un ValidationError. Este error se captura en el bloque try...catch y, si es una instancia de ValidationError, se registra un mensaje específico.
Manejar Múltiples Tipos de Errores Personalizados
Es posible que quieras crear varios tipos de errores para diferentes partes de tu aplicación. Así puedes manejar múltiples errores personalizados:
Esta estructura permite manejar de forma distinta cada tipo de error, haciendo que la aplicación sea más robusta y fácil de depurar.
Prefiere instanceof sobre comparar strings de error.name cuando puedas: instanceof también coincide con las subclases, por lo que sobrevive mejor a las refactorizaciones.
Construir una Jerarquía de Errores con una Clase Base
En aplicaciones reales vale la pena darle a todos tus errores un ancestro común. Un manejador de nivel superior puede entonces capturar todos los errores "esperados" de la aplicación en un solo lugar, mientras el código más profundo lanza subtipos precisos. La opción cause (ES2022) permite que un error de nivel superior envuelva al de nivel inferior que lo provocó, conservando el original para depuración.
Aquí this.name = this.constructor.name elimina la necesidad de repetir el nombre en cada subclase, y la única comprobación instanceof AppError captura NotFoundError, ConflictError y cualquier subtipo futuro.
Manejo Avanzado de Errores Personalizados en JavaScript
Ampliando las bases, podemos aplicar errores personalizados a escenarios más complejos como operaciones asíncronas y casos de lógica de negocio específica.
Ejemplo 1: Manejo de Errores de API Personalizado
Este ejemplo muestra cómo crear y usar un error personalizado para manejar problemas en solicitudes de API, como cuando un recurso solicitado no se encuentra o el servidor devuelve un error. El flujo async/await aquí se combina con el manejo de errores con promesas.
Explicación
- Clase ApiError: Esta clase personalizada captura errores específicos de la API, almacenando el código de estado HTTP junto con un mensaje personalizado.
- Función fetchData: Intenta obtener datos de una URL proporcionada. Si la respuesta no es exitosa, lanza un
ApiErrorcon un mensaje detallado y el código de estado. - Manejo de errores: Los errores se capturan y manejan apropiadamente. Los errores relacionados con la API se registran con información detallada, mientras que los errores inesperados también se capturan y registran.
Ejemplo 2: Manejo de Errores de Validación Personalizado
Usa este ejemplo para manejar errores relacionados con la validación de datos, como la verificación de la entrada del usuario.
Explicación
- Clase ValidationError: Una clase de error personalizada que ayuda a identificar qué campo específico de los datos de entrada no superó la validación.
- Función validateUser: Comprueba la validez de los datos del usuario. Si los datos no cumplen ciertos criterios, lanza un
ValidationError. - Manejo de errores: Captura los errores de validación y los registra con información detallada. Los demás tipos de errores también se manejan por separado.
Buenas Prácticas y Advertencias
- Llama siempre a
super(message)primero, antes de tocarthis. - Establece
namepara que los registros ytoString()sean legibles;this.name = this.constructor.namelo hace una sola vez para toda una jerarquía. - Prefiere
instanceofsobre comparaciones deerror.name— también coincide con las subclases. - Relanza lo que no reconoces. Un
catchque se traga todo (catch (e) {}) oculta errores reales. Maneja tus tipos conocidos y hazthrow errorpara el resto, como hacen los ejemplos. - Usa
causepara envolver, no para reemplazar. Cuando capturas un error de bajo nivel y lanzas uno de alto nivel, pasa{ cause: original }para que el stack trace y la causa raíz sobrevivan. - No subclasifiques
Errorpara controlar el flujo. Los errores son para condiciones excepcionales, no para ramificaciones normales.
Conclusión
Crear clases de error personalizadas en JavaScript extendiendo la clase Error es una técnica poderosa para manejar tipos específicos de errores de forma más granular. Mejora la claridad y la mantenibilidad del manejo de errores en tu código, permitiéndote ofrecer comentarios y acciones más específicas según las diferentes condiciones de error. Este método no solo ayuda en la depuración, sino que también mejora la fiabilidad de tus aplicaciones al garantizar que cada tipo de error se capture y maneje adecuadamente.