ProgramaciónDesarrollador Backend

Describe cómo funciona el mecanismo de tipos de errores personalizados (Custom Errors) en TypeScript. ¿Cómo declarar correctamente las clases de errores personalizados, por qué es importante especificar su tipo y cómo evitar trampas con 'instanceof' y la serialización de errores?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia de la pregunta: En JavaScript, los errores estándar se describen a través de la clase Error. En grandes proyectos de TypeScript, es importante utilizar su propia jerarquía de errores para un manejo preciso de situaciones, pero hay matices con tipos, herencia y el comportamiento de 'instanceof'.

Problema: Al heredar de Error pueden surgir dificultades: se pierde el prototipo, 'instanceof' no funciona correctamente, los tipos pueden estar mal descritos y la serialización a menudo conduce a la pérdida de stack trace. Sin una especificación clara de las propiedades, se pueden obtener errores al manejar las excepciones.

Solución: Definir correctamente los errores personalizados ampliando la clase Error. Se debe especificar explícitamente el nombre, restaurar el prototipo manualmente (importante para ES5 y al compilar a CommonJS), y tipificar los campos de los errores.

Ejemplo de código:

class ValidationError extends Error { code: number; constructor(message: string, code: number = 400) { super(message); Object.setPrototypeOf(this, ValidationError.prototype); this.name = 'ValidationError'; this.code = code; } } function process(user: string) { if (!user) throw new ValidationError('User required', 401); }

Características clave:

  • Restauración explícita del prototipo para soportar 'instanceof' incluso al transpilar.
  • Tipificación de las propiedades personalizadas de los errores.
  • Clase individual para cada grupo lógico de errores.

Preguntas trampa.

¿Por qué no se puede omitir la llamada a Object.setPrototypeOf(this, ...)?

Si no se llama a Object.setPrototypeOf(this, Class.prototype), 'instanceof' ValidationError no funcionará al compilar a ES5/CommonJS o Babel. Esto hará que los bloques catch de ValidationError no intercepten el error.

class CustomErr extends Error {} const err = new CustomErr('msg'); console.log(err instanceof CustomErr); // false sin setPrototypeOf

¿Se puede omitir el campo name en un error personalizado?

Si no se establece la propiedad this.name, el stack del error y la visualización en los logs serán incorrectos, lo que complicará la búsqueda de la causa y la clasificación de los errores.

¿Es necesario hacer que los errores sean serializables, y si es así, cómo?

Los errores deben poder serializarse correctamente (por ejemplo, para logging o transmisión en red), de lo contrario, JSON.stringify(new Error()) no devolverá message y stack. Se debe sobreescribir el método toJSON.

class SerializableError extends Error { toJSON() { return { name: this.name, message: this.message, stack: this.stack }; } }

Errores comunes y anti-patrones

  • La ausencia de Object.setPrototypeOf provoca un funcionamiento incorrecto de instanceof
  • Ignorar name y propiedades personalizadas
  • Serialización del error sin implementar toJSON: se pierden stack/message

Ejemplo de la vida real

Caso negativo

En el proyecto se hizo simplemente class MyError extends Error, sin restaurar el prototipo. Los errores se capturaban mediante if (err instanceof MyError), pero esto no funcionaba, y el código silenciosamente pasaba por alto el manejo de situaciones críticas.

Pros:

  • El código lucía conciso
  • No había boilerplate

Contras:

  • instanceof no funcionaba
  • Las excepciones no se registraban correctamente
  • Al cambiar de ts->js transpiler apareció incompatibilidad

Caso positivo

Se implementó correctamente CustomError, especificando claramente el name, code y toJSON, y se cubrieron las pruebas para el manejo de diferentes tipos de errores. En los logs y manejadores catch, la estructura de los errores se volvió clara, lo que redujo el tiempo de búsqueda de bugs.

Pros:

  • Claridad en la jerarquía tipificada de errores
  • Serialización confiable
  • Multiplataforma entre el navegador y Node.js

Contras:

  • Surgió lógica repetitiva en cada clase de CustomError