ProgrammazioneSviluppatore Backend

Descrivi come funziona il meccanismo dei tipi di errori personalizzati (Custom Errors) in TypeScript. Come dichiarare correttamente le classi di errori personalizzati, perché è importante specificarne il tipo, e come evitare trappole con 'instanceof' e la serializzazione degli errori?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della questione: In JavaScript, gli errori standard sono descritti tramite la classe Error. In grandi progetti TypeScript, è importante utilizzare la propria gerarchia di errori per una gestione precisa delle situazioni, ma ci sono delle sfide relative ai tipi, all'ereditarietà e al comportamento di 'instanceof'.

Problema: Erediterando da Error possono sorgere difficoltà: si perde il prototipo, 'instanceof' non funziona correttamente, i tipi possono essere descritti in modo errato, la serializzazione porta spesso alla perdita dello stack trace. Senza specificare esplicitamente le proprietà, si possono verificare bug nella gestione degli errori.

Soluzione: Definire correttamente gli errori personalizzati estendendo la classe Error. È necessario specificare esplicitamente il nome, ripristinare manualmente il prototipo (importante per ES5 e durante la compilazione in CommonJS), e tipizzare i campi degli errori.

Esempio di codice:

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); }

Caratteristiche chiave:

  • Ripristino esplicito del prototipo per supportare 'instanceof' anche durante la transpilation.
  • Tipizzazione delle proprietà personalizzate degli errori.
  • Classe individuale per ogni gruppo logico di errori.

Domande trabocchetto.

Perché non si può omettere la chiamata a Object.setPrototypeOf(this, ...)?

Se non si chiama Object.setPrototypeOf(this, Class.prototype), 'instanceof' ValidationError non funzionerà quando compilato in ES5/CommonJS o Babel. Questo porterà al fatto che i blocchi catch di ValidationError non cattureranno l'errore.

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

Si può omettere il campo name nell'errore personalizzato?

Se non si imposta la proprietà this.name, lo stack dell'errore e la visualizzazione nei log saranno errati, rendendo difficile la ricerca delle cause e la classificazione degli errori.

È necessario rendere gli errori serializzabili, e se sì, come?

Gli errori devono essere correttamente serializzati (ad esempio, per il logging o la trasmissione in rete), altrimenti JSON.stringify(new Error()) non restituirà message e stack. È necessario sovrascrivere il metodo toJSON.

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

Errori tipici e anti-pattern

  • L'assenza di Object.setPrototypeOf porta a un funzionamento errato di instanceof
  • Ignorare name e proprietà personalizzate
  • Serializzazione dell'errore senza implementare toJSON: perdita di stack/message

Esempio dalla vita reale

Caso negativo

Nel progetto è stato realizzato semplicemente class MyError extends Error, senza ripristinare il prototipo. Gli errori venivano catturati tramite if (err instanceof MyError), ma questo non funzionava, e il codice ignorava silenziosamente la gestione delle situazioni critiche.

Vantaggi:

  • Il codice sembrava conciso
  • Non c'era boilerplate

Svantaggi:

  • instanceof non funzionava
  • Le eccezioni non venivano registrate correttamente
  • Con il cambio del transpiler da ts a js è emersa un'incompatibilità

Caso positivo

È stato implementato correttamente CustomError, specificando esplicitamente name, code e toJSON, con test che coprivano la gestione di diversi tipi di errori. Nei log e nei gestori catch la struttura degli errori è diventata chiara, il che ha ridotto il tempo necessario a trovare bug.

Vantaggi:

  • Chiara gerarchia dei tipi di errori
  • Serializzazione affidabile
  • Cross-platform tra browser e Node.js

Svantaggi:

  • È comparsa logica boilerplate in ogni classe CustomError