Tratamento de Erros em TypeScript: do try/catch a cenários complexos
TypeScript, sendo uma extensão do JavaScript, herda e expande os mecanismos de tratamento de erros. O tratamento adequado de exceções é a chave para uma aplicação estável e previsível. Neste artigo, abordaremos todos os aspectos do trabalho com erros: desde o básico try/catch até a criação de suas próprias classes de erro tipadas e estratégias avançadas.
Sintaxe Básica: try, catch, finally
O mecanismo principal de tratamento de erros em TypeScript (assim como em JavaScript) é a construção try...catch...finally. Ela permite capturar exceções que ocorrem no código e reagir a elas.
function parseJSON(data: string): object { try { return JSON.parse(data); } catch (error) { console.error('Erro ao fazer parse do JSON:', error); return {}; }}
parseJSON('{"name": "TypeScript"}'); // { name: 'TypeScript' }parseJSON('JSON inválido'); // {} (erro capturado)O bloco finally é executado em qualquer caso — tanto após a conclusão bem-sucedida do try quanto após a captura de um erro. É o local ideal para limpeza de recursos (fechamento de arquivos, conexões).
function processData(data: string): void { let resource: any = null; try { resource = acquireResource(); // ... código perigoso } catch (error) { console.error('Erro de processamento:', error); } finally { if (resource) { resource.release(); // limpeza garantida } }}Tipagem de Erros: o problema do unknown
Uma característica chave do TypeScript — no bloco catch, a variável error tem por padrão o tipo unknown (a partir do TS 4.0). Isso foi feito intencionalmente para forçar o desenvolvedor a verificar explicitamente o tipo do erro, em vez de assumir que é um Error.
try { // algum código} catch (error) { // error tem tipo unknown // Erro: a propriedade 'message' não existe no tipo 'unknown' // console.log(error.message);
// Abordagem correta — verificação de tipo if (error instanceof Error) { console.log('Mensagem:', error.message); } else { console.log('Erro desconhecido:', error); }}Por que isso é importante? Em JavaScript, qualquer coisa pode cair no bloco catch: string, número, objeto, null ou até undefined. A verificação de tipo forçada protege contra erros em tempo de execução.
Criação de Classes de Erro Personalizadas
Para aplicações complexas, muitas vezes é necessário distinguir tipos de erros. Em TypeScript, é fácil criar uma hierarquia de suas próprias classes de erro, estendendo o Error embutido.
// Classe base para erros da aplicaçãoclass AppError extends Error { public readonly statusCode: number; public readonly isOperational: boolean;
constructor(message: string, statusCode: number = 500, isOperational: boolean = true) { super(message); this.name = this.constructor.name; this.statusCode = statusCode; this.isOperational = isOperational;
// Restaura o protótipo (importante para instanceof) Object.setPrototypeOf(this, new.target.prototype); }}
// Tipos específicos de erroclass ValidationError extends AppError { public readonly field: string;
constructor(message: string, field: string) { super(message, 400); this.field = field; }}
class NotFoundError extends AppError { constructor(message: string = 'Recurso não encontrado') { super(message, 404); }}
// Usofunction getUser(id: number): User { if (id <= 0) { throw new ValidationError('O ID deve ser um número positivo', 'id'); } // ... busca do usuário throw new NotFoundError