W3docs

Errori personalizzati in JavaScript

JavaScript consente di creare tipi di errore personalizzati estendendo la classe Error integrata, per una gestione degli errori più dettagliata.

Errori personalizzati in JavaScript

JavaScript consente di creare tipi di errore personalizzati estendendo la classe Error integrata. Un errore personalizzato è semplicemente una classe che eredita da Error (o da un altro tipo di errore) e porta un name significativo più eventuali dati aggiuntivi richiesti dalla situazione.

Questa pagina tratta il perché si vogliono usare errori personalizzati, come definirli correttamente, come distinguere i tipi di errore con instanceof, come allegare contesto (codici di stato, nomi di campo, la cause originale) e come organizzare una gerarchia di errori per un'applicazione reale.

Perché creare errori personalizzati?

Lanciare un semplice new Error("...") funziona, ma fornisce al chiamante solo una stringa da esaminare. Gli errori personalizzati risolvono tre problemi:

  • Gestione basata sul tipo. Con instanceof ValidationError si può reagire a un tipo specifico di fallimento senza analizzare il testo del messaggio, che è fragile e dipendente dalla lingua.
  • Contesto aggiuntivo. Una classe personalizzata può portare campi strutturati — un statusCode HTTP, il field incriminato, un suggerimento per il nuovo tentativo — invece di concentrare tutto nel messaggio.
  • Gerarchie chiare. Una classe base condivisa (ad esempio AppError) consente a un gestore di primo livello di intercettare tutti gli errori dell'applicazione con un singolo instanceof, pur permettendo al codice interno di lanciare sottotipi specifici.

Se si ha bisogno di imparare prima i meccanismi di lancio/cattura, leggere Gestione degli errori: try...catch. Gli errori personalizzati si basano direttamente sull'ereditarietà delle classi e sull'estensione delle classi integrate.

Nozioni di base sull'estensione della classe Error

Per creare un errore personalizzato, si usa extend sulla classe Error. La nuova classe eredita message, stack e toString() di Error, e si aggiunge tutto ciò che serve.

Creazione di una classe di errore personalizzata

Ecco il pattern minimale:

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"
  }
}

Due dettagli sono importanti:

  • super(message) deve venire prima. All'interno del costruttore di una sottoclasse non è possibile usare this prima di chiamare super(). Il costruttore di Error imposta this.message e cattura lo stack trace.
  • Impostare this.name. Senza di esso, l'errore viene riportato come "Error" nei messaggi e in toString(). Impostare name rende leggibili i log e il pattern switch (error.name).

In alcuni esempi si può vedere anche Object.setPrototypeOf(this, new.target.prototype). Con i transpiler moderni e le classi native è di solito non necessario, ma non causa danni e garantisce che instanceof funzioni anche quando il codice viene compilato in ES5 o condiviso tra realm (iframe/worker boundary). Gli esempi qui sotto lo mantengono per sicurezza.

Una volta creato, l'errore si comporta come qualsiasi altro:

const e = new ValidationError("bad input");
e.name;               // "ValidationError"
e instanceof Error;   // true  — it is still a real Error
e.toString();         // "ValidationError: bad input"

Utilizzo degli errori personalizzati

Una volta definito un errore personalizzato, è possibile lanciarlo nell'applicazione come qualsiasi errore standard:

javascript— editable

In questo esempio, un'email viene convalidata rispetto a un'espressione regolare. Se la validazione fallisce, viene lanciato un ValidationError. Questo errore viene poi catturato nel blocco try...catch e, se è un'istanza di ValidationError, viene registrato un messaggio specifico.

Gestione di più tipi di errori personalizzati

Potrebbe essere necessario creare vari tipi di errori per diverse parti dell'applicazione. Ecco come gestire più errori personalizzati:

javascript— editable

Questa impostazione consente una gestione distinta dei diversi tipi di errore, rendendo l'applicazione più robusta e facile da eseguire il debug.

Preferire instanceof al confronto delle stringhe error.name quando possibile: instanceof corrisponde anche alle sottoclassi, quindi è più resistente al refactoring.

Costruire una gerarchia di errori con una classe base

Nelle applicazioni reali conviene dare a tutti gli errori un antenato comune. Un gestore di primo livello può quindi intercettare ogni errore "atteso" dell'applicazione in un unico punto, pur permettendo al codice più profondo di lanciare sottotipi precisi. L'opzione cause (ES2022) consente a un errore di livello superiore di avvolgere quello di livello inferiore che lo ha causato, preservando l'originale per il debug.

javascript— editable

Qui this.name = this.constructor.name elimina la necessità di ripetere il nome in ogni sottoclasse, e il singolo controllo instanceof AppError cattura NotFoundError, ConflictError e qualsiasi futuro sottotipo.

Gestione avanzata degli errori personalizzati in JavaScript

Ampliando le nozioni di base, possiamo applicare gli errori personalizzati a scenari più complessi come le operazioni asincrone e i casi di logica di business specifici.

Esempio 1: Gestione personalizzata degli errori API

Questo esempio mostra come creare e utilizzare un errore personalizzato per gestire i problemi delle richieste API, ad esempio quando una risorsa richiesta non viene trovata o il server restituisce un errore. Il flusso async/await qui si abbina alla gestione degli errori con le promise.

javascript— editable

Spiegazione

  • Classe ApiError: Questa classe personalizzata cattura gli errori specifici delle API, memorizzando il codice di stato HTTP insieme a un messaggio personalizzato.
  • Funzione fetchData: Tenta di recuperare dati da un URL fornito. Se la risposta non ha successo, lancia un ApiError con un messaggio dettagliato e il codice di stato.
  • Gestione degli errori: Gli errori vengono catturati e gestiti in modo appropriato. Gli errori relativi alle API vengono registrati con informazioni dettagliate, mentre anche gli errori imprevisti vengono catturati e registrati.

Esempio 2: Gestione personalizzata degli errori di validazione

Utilizzare questo esempio per gestire gli errori relativi alla validazione dei dati, ad esempio il controllo dell'input dell'utente.

javascript— editable

Spiegazione

  • Classe ValidationError: Una classe di errore personalizzata che aiuta a identificare quale campo specifico dei dati di input non ha superato il controllo di validazione.
  • Funzione validateUser: Verifica la validità dei dati dell'utente. Se i dati non soddisfano determinati criteri, lancia un ValidationError.
  • Gestione degli errori: Cattura gli errori di validazione e li registra con informazioni dettagliate. Anche gli altri tipi di errori vengono gestiti separatamente.

Best practice e insidie comuni

  • Chiamare sempre super(message) prima, prima di toccare this.
  • Impostare name affinché i log e toString() siano leggibili; this.name = this.constructor.name lo fa una volta per tutta una gerarchia.
  • Preferire instanceof ai confronti con error.name — corrisponde anche alle sottoclassi.
  • Rilancia ciò che non riconosci. Un catch che inghiotte tutto (catch (e) {}) nasconde bug reali. Gestisci i tipi noti e usa throw error per il resto, come mostrano gli esempi.
  • Usare cause per avvolgere, non sostituire. Quando si cattura un errore di basso livello e se ne lancia uno di livello superiore, passare { cause: original } affinché lo stack trace e la causa radice sopravvivano.
  • Non usare sottoclassi di Error per controllare il flusso. Gli errori sono per condizioni eccezionali, non per la normale ramificazione del codice.

Conclusione

Creare classi di errore personalizzate in JavaScript estendendo la classe Error è una tecnica potente per gestire tipi specifici di errori in modo più granulare. Migliora la chiarezza e la manutenibilità della gestione degli errori nel codice, consentendo di fornire feedback e azioni più specifici in base alle diverse condizioni di errore. Questo metodo non solo aiuta nel debug, ma migliora anche l'affidabilità delle applicazioni assicurando che ogni tipo di errore venga catturato e gestito in modo appropriato.

Pratica

Pratica
Qual è lo scopo dell'utilizzo di classi di errore estese in JavaScript?
Qual è lo scopo dell'utilizzo di classi di errore estese in JavaScript?
Pratica
Nel costruttore di una sottoclasse di errore personalizzata, perché super(message) deve essere chiamato prima di usare this?
Nel costruttore di una sottoclasse di errore personalizzata, perché super(message) deve essere chiamato prima di usare this?
Pratica
Cosa consente di fare l'opzione cause di ES2022 quando si lancia un errore personalizzato?
Cosa consente di fare l'opzione cause di ES2022 quando si lancia un errore personalizzato?
Was this page helpful?