W3docs

Erros Personalizados em JavaScript

JavaScript permite criar tipos de erro personalizados estendendo a classe Error nativa, possibilitando um tratamento de erros mais detalhado.

Erros Personalizados em JavaScript

O JavaScript permite criar seus próprios tipos de erro estendendo a classe Error nativa. Um erro personalizado é simplesmente uma classe que herda de Error (ou de outro tipo de erro) e carrega um name significativo, além de quaisquer dados extras que a situação exigir.

Esta página aborda por que você desejaria usar erros personalizados, como defini-los corretamente, como distinguir tipos de erro com instanceof, como adicionar contexto (códigos de status, nomes de campos, o cause original) e como organizar uma hierarquia de erros para uma aplicação real.

Por que criar erros personalizados?

Lançar um simples new Error("...") funciona, mas oferece ao chamador apenas uma string para inspecionar. Os erros personalizados resolvem três problemas:

  • Tratamento baseado em tipo. Com instanceof ValidationError você pode reagir a um tipo específico de falha sem precisar analisar o texto da mensagem, o que é frágil e dependente de localização.
  • Contexto adicional. Uma classe personalizada pode carregar campos estruturados — um statusCode HTTP, o field problemático, uma dica de nova tentativa — em vez de comprimir tudo na mensagem.
  • Hierarquias claras. Uma classe base comum (por exemplo, AppError) permite que um handler de nível superior capture todos os erros da sua aplicação com um único instanceof, ao mesmo tempo que permite que o código interno lance subtipos específicos.

Se você precisa aprender primeiro a mecânica de lançamento/captura, leia Tratamento de erros: try...catch. Os erros personalizados se baseiam diretamente em herança de classes e extensão de classes nativas.

Fundamentos da Extensão da Classe Error

Para criar um erro personalizado, você extend a classe Error. A nova classe herda message, stack e toString() de Error, e você adiciona o que mais precisar.

Criando uma Classe de Erro Personalizada

Este é o padrão mínimo:

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

Dois detalhes são importantes:

  • super(message) deve vir primeiro. Dentro do construtor de uma subclasse, você não pode usar this antes de chamar super(). O construtor de Error define this.message e captura o stack trace.
  • Defina this.name. Sem isso, o erro aparece como "Error" em mensagens e em toString(). Definir name torna os logs e o padrão switch (error.name) mais legíveis.

Você também pode encontrar Object.setPrototypeOf(this, new.target.prototype) em alguns exemplos. Com transpiladores modernos e classes nativas, isso geralmente é desnecessário, mas não causa problemas e garante que instanceof funcione mesmo quando o código é compilado para ES5 ou compartilhado entre realms (iframes/fronteiras de worker). Os exemplos abaixo mantêm isso por segurança.

Uma vez criado, o erro se comporta como qualquer outro:

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

Usando Erros Personalizados

Depois de definir um erro personalizado, você pode lançá-lo na sua aplicação como qualquer erro padrão:

javascript— editable

Neste exemplo, um e-mail é validado contra uma expressão regular. Se a validação falhar, um ValidationError é lançado. Esse erro é então capturado no bloco try...catch e, se for uma instância de ValidationError, uma mensagem específica é registrada.

Tratando Múltiplos Tipos de Erros Personalizados

Você pode querer criar vários tipos de erros para diferentes partes da sua aplicação. Veja como tratar múltiplos erros personalizados:

javascript— editable

Essa estrutura permite o tratamento distinto de diferentes tipos de erro, tornando a aplicação mais robusta e fácil de depurar.

Prefira instanceof em vez de comparar strings error.name quando possível: instanceof também corresponde a subclasses, portanto sobrevive melhor a refatorações.

Construindo uma Hierarquia de Erros com uma Classe Base

Em aplicações reais, vale a pena dar a todos os seus erros um ancestral comum. Um handler de nível superior pode então capturar todos os erros "esperados" da aplicação em um único lugar, ao mesmo tempo que permite que o código mais interno lance subtipos precisos. A opção cause (ES2022) permite que um erro de nível superior envolva o erro de nível inferior que o desencadeou, preservando o original para depuração.

javascript— editable

Aqui, this.name = this.constructor.name elimina a necessidade de repetir o nome em cada subclasse, e a única verificação instanceof AppError captura NotFoundError, ConflictError e qualquer subtipo futuro.

Tratamento Avançado de Erros Personalizados em JavaScript

Expandindo os conceitos básicos, podemos aplicar erros personalizados a cenários mais complexos, como operações assíncronas e casos específicos de lógica de negócio.

Exemplo 1: Tratamento Personalizado de Erros de API

Este exemplo demonstra como criar e usar um erro personalizado para lidar com problemas em requisições de API, como quando um recurso solicitado não é encontrado ou o servidor retorna um erro. O fluxo async/await aqui se combina com o tratamento de erros com promises.

javascript— editable

Explicação

  • Classe ApiError: Esta classe personalizada captura erros específicos de API, armazenando o código de status HTTP junto com uma mensagem personalizada.
  • Função fetchData: Tenta buscar dados de uma URL fornecida. Se a resposta não for bem-sucedida, lança um ApiError com uma mensagem detalhada e o código de status.
  • Tratamento de Erros: Os erros são capturados e tratados adequadamente. Erros relacionados à API são registrados com informações detalhadas, enquanto erros inesperados também são capturados e registrados.

Exemplo 2: Tratamento Personalizado de Erros de Validação

Use este exemplo para tratar erros relacionados à validação de dados, como a verificação de entrada do usuário.

javascript— editable

Explicação

  • Classe ValidationError: Uma classe de erro personalizada que ajuda a identificar qual campo específico dos dados de entrada falhou na verificação de validação.
  • Função validateUser: Verifica a validade dos dados do usuário. Se os dados não atenderem a determinados critérios, lança um ValidationError.
  • Tratamento de Erros: Captura erros de validação e os registra com informações detalhadas. Outros tipos de erros também são tratados separadamente.

Boas Práticas e Armadilhas

  • Sempre chame super(message) primeiro, antes de usar this.
  • Defina name para que os logs e toString() sejam legíveis; this.name = this.constructor.name faz isso uma vez para toda uma hierarquia.
  • Prefira instanceof em vez de comparações com error.name — ele também corresponde a subclasses.
  • Relance o que você não reconhece. Um catch que engole tudo (catch (e) {}) esconde bugs reais. Trate seus tipos conhecidos e use throw error para o restante, como os exemplos demonstram.
  • Use cause para envolver, não substituir. Quando você captura um erro de baixo nível e lança um de alto nível, passe { cause: original } para que o stack trace e a causa raiz sejam preservados.
  • Não herde de Error para controlar o fluxo. Erros são para condições excepcionais, não para ramificações normais.

Conclusão

Criar classes de erro personalizadas em JavaScript estendendo a classe Error é uma técnica poderosa para lidar com tipos específicos de erros de forma mais granular. Isso aumenta a clareza e a manutenibilidade do tratamento de erros no seu código, permitindo fornecer feedbacks e ações mais específicas com base em diferentes condições de erro. Esse método não apenas ajuda na depuração, mas também melhora a confiabilidade das suas aplicações, garantindo que cada tipo de erro seja capturado e tratado adequadamente.

Prática

Prática
Qual é o propósito de usar classes de erro estendidas em JavaScript?
Qual é o propósito de usar classes de erro estendidas em JavaScript?
Prática
No construtor de uma subclasse de erro personalizada, por que super(message) deve ser chamado antes de usar this?
No construtor de uma subclasse de erro personalizada, por que super(message) deve ser chamado antes de usar this?
Prática
O que a opção cause do ES2022 permite fazer ao lançar um erro personalizado?
O que a opção cause do ES2022 permite fazer ao lançar um erro personalizado?
Was this page helpful?