Estoy trabajando en una aplicación compleja con diferentes tipos de errores, servicios y conceptos de dominio.
Para arrojar errores de "objeto", hay dos enfoques diferentes que me vienen a la mente:
Object.assign() a un objeto de error (opción fácil si solo necesito lanzar uno o un par de errores que siguen a este formulario): function f() { const err = new Error(); Object.assign(err, { name: "ServiceError", code: "service/some-string-code", message: "Some message", }); throw err; } try { f(); } catch(err) { console.log(err instanceof Error); } class MyServiceError extends Error { constructor(code, message) { super(message); this.name = "ServiceError"; this.code = code; } } function f() { const err = new MyServiceError("service/some-string-code", "Some message"); throw err; } try { f(); } catch(err) { console.log(err instanceof Error); console.log(err instanceof MyServiceError); }¿Cuáles son los pros y los contras entre ambas "definiciones de errores personalizados"?
Además, si elijo el segundo enfoque, parece que necesitaré crear múltiples clases CustomError para diferentes conceptos de dominio, servicios, etc. para lograr un código simétrico y una arquitectura limpia... (???) Que en A su vez, veo como reinventar la rueda y agregar código innecesario, porque quizás no todos los conceptos de la aplicación deberían necesitar un tipo personalizado de excepción.
¿Se consideran ambas prácticas válidas en JavaScript?
Nota: lanzar objetos o cadenas o cosas así me parece muy malo, ya que no podemos obtener el seguimiento de la pila, validar instancias, etc.
// This seems bad to me. Isn't it an anti-pattern? throw { code: "", message: "", name: "" }El enfoque Object.assign es menos robusto y más un truco, es mejor crear una clase de error personalizada. Ya hay una discusión en profundidad sobre SO.
Como desea usar campos adicionales, como máximo, introduzca 2-3 clases personalizadas para errores internos, pero incluso eso a menudo es excesivo:
NetworkError con ubicación, ruta y estadoUiError con componente y estado de datos problemático y tal vez un código de mensaje para i18nRuntimeError genérico, o similar, para casos desconocidos No tiene mucho sentido tener una clase de error por cada ocurrencia potencial. A diferencia de Java, no hay excepciones verificadas en JavaScript, y el objetivo es tener los datos suficientes para solucionar el problema, sin sobrediseñarlo. Si puede capturar de manera significativa y luego mostrar en un cuadro de diálogo más datos de los que cabría la cadena de message , hágalo.
Al diseñar errores personalizados, comience con dónde y cómo procesará y mostrará esta información. Luego, vea si puede recopilar fácilmente estos datos donde los arroja. Si no tiene un cuadro de diálogo de error global o un informe de error centralizado, tal vez solo el error predeterminado sea suficiente y pueda colocar todos los datos en el mensaje.
Hay un caso especial, cuando desea utilizar errores como medio para controlar la lógica. Trate de evitarlo tanto como sea posible, JavaScript es muy flexible para no usar throw como una forma de permitir que la capa superior elija una ruta de ejecución diferente. Sin embargo, a veces se usa para volver a intentar las solicitudes de red y luego debería tener suficientes datos para eso.
El objeto de error incorporado ya tiene los siguientes campos:
En cada error, la stack y message son dos piezas de información cruciales que ayudan a solucionar el problema. Por lo tanto, es importante, cuando lo vuelvas a lanzar, usar algo como esto (para todo lo que no sea IE):
catch (err) { throw new Error('New error message with added info', { cause: err }); }Por último, es útil verificar lo que otros están haciendo:
Y, JavaScript no solo tiene Error , sino también:
También puedes tirarlos cuando sea apropiado.
Tenga en cuenta que la mayoría de los marcos de interfaz de usuario que manejan las vistas no tienen clases de error personalizadas ni las necesitan.