Lección 16 · 16 de 20
Errores propios y finally · JavaScript
Cree en JavaScript sus propias clases de error con extends Error, encadene la causa con cause y libere recursos siempre con finally.

Para distinguir unos fallos de otros conviene crear clases de error propias que hereden de Error. AppError es la base de la aplicación: llama a super(message, options) y pone en name el nombre de la clase real con this.constructor.name, de modo que cada subclase se presenta sola como ValidationError o PaymentError sin repetir código.
Las subclases pueden llevar datos extra: ValidationError guarda el campo que ha fallado en field. PaymentError no necesita nada más que su nombre, así que basta con class PaymentError extends AppError {}. El segundo argumento de Error, { cause }, encadena el error original: el rechazo del pago conserva el motivo técnico en err.cause.
En el catch, `instanceof` decide qué hacer con cada tipo de error: un aviso sobre el campo o un mensaje de pago rechazado. Los errores que no reconoce se vuelven a lanzar con throw err, para no ocultar fallos inesperados, como un error de programación.
El bloque `finally` se ejecuta siempre, tanto si try termina bien como si salta un error, e incluso si dentro hay un return. Por eso cada pedido escribe closed: es el sitio para liberar recursos, cerrar ficheros o conexiones y dejarlo todo en orden.
Código · main.js
class AppError extends Error { constructor(message, options) { super(message, options); // options can carry { cause } this.name = this.constructor.name; // "ValidationError", "PaymentError"... }}class ValidationError extends AppError { constructor(field, message) { super(message); this.field = field; }}class PaymentError extends AppError {}function charge(order) { if (!order.email) throw new ValidationError("email", "an email is required"); if (order.amount > 500) { throw new PaymentError(`order ${order.id} declined`, { cause: new Error("card limit is 500 EUR") }); } return `Order ${order.id} paid: ${order.amount} EUR`;}const orders = [{ id: 1, email: "ana@shop.test", amount: 80 }, { id: 2, amount: 20 }, { id: 3, email: "luis@shop.test", amount: 900 }];for (const order of orders) { try { console.log(charge(order)); } catch (err) { if (err instanceof ValidationError) console.log(`${err.name} in "${err.field}": ${err.message}`); else if (err instanceof PaymentError) console.log(`${err.name}: ${err.message} (${err.cause.message})`); else throw err; // unknown errors keep travelling up } finally { console.log(` order ${order.id} closed`); // runs whether it failed or not }}Salida · node main.js
Order 1 paid: 80 EUR order 1 closed ValidationError in "email": an email is required order 2 closed PaymentError: order 3 declined (card limit is 500 EUR) order 3 closed
Para recordar
- Las clases de error propias heredan de
Errory fijan suname. - Un error puede llevar datos extra y su causa en
{ cause }. instanceofdistingue los tipos de error en elcatch.- Los errores desconocidos se vuelven a lanzar.
finallyse ejecuta siempre, haya error o no.
Ejercicio
Cree una clase StockError con una propiedad item, lánzela desde charge cuando el pedido tenga item: "lamp" y añada su caso en el catch.