Tratamento de Erros em TypeScript: do try/catch ao Código Robusto
TypeScript adiciona tipagem estática ao JavaScript, mas erros em tempo de execução continuam sendo uma parte essencial do desenvolvimento. O tratamento incorreto de exceções pode levar à queda da aplicação, vazamento de dados ou funcionamento incorreto da interface do usuário. Neste artigo, vamos analisar como tratar erros de forma eficaz em TypeScript, usando mecanismos nativos e padrões avançados.
try/catch básico em TypeScript
A construção try/catch é a base do tratamento de erros. Em TypeScript, ao contrário do JavaScript, podemos tipar o erro capturado. No entanto, há uma nuance importante: por padrão, o tipo do erro no bloco catch é unknown, e não Error.
try { const data = JSON.parse('json inválido'); console.log(data);} catch (error) { // error tem tipo unknown if (error instanceof Error) { console.error('Ocorreu um erro:', error.message); } else { console.error('Erro desconhecido:', error); }}Por que isso é importante? Em JavaScript, você pode lançar qualquer coisa: string, número, objeto. O TypeScript nos protege contra acesso inseguro às propriedades do erro sem verificação. Recomenda-se sempre verificar o tipo do erro antes de usá-lo.
Classes de erro personalizadas
Para um tratamento mais preciso, crie suas próprias classes de erro, estendendo o Error nativo. Isso permite distinguir tipos de erro e transmitir informações adicionais.
class ValidationError extends Error { constructor( public field: string, message: string ) { super(message); this.name = 'ValidationError'; }}
class NetworkError extends Error { constructor( public statusCode: number, message: string ) { super(message); this.name = 'NetworkError'; }}
function processUserData(data: unknown): void { if (!data || typeof data !== 'object') { throw new ValidationError('data', 'Dados inválidos'); } if (!('email' in data)) { throw new ValidationError('email', 'Email é obrigatório'); }}
try { processUserData({ name: 'Ivan' });} catch (error) { if (error instanceof ValidationError) { console.error(`Erro de validação do campo ${error.field}: ${error.message}`); } else if (error instanceof NetworkError) { console.error(`Erro de rede ${error.statusCode}: ${error.message}`); } else { console.error('Erro desconhecido:', error); }}Essa abordagem torna o código autodocumentado e simplifica a depuração. Você sempre sabe onde e por que ocorreu um erro.
Tipagem de funções com erros: never e discriminated unions
O TypeScript fornece ferramentas poderosas para trabalhar com erros no nível de tipos. Use o tipo never para funções que sempre lançam exceções e discriminated unions para retornar erros.
function throwError(message: string): never { throw new Error(message);}
// Discriminated union para o resultadotype Result<T> = | { success: true; data: T } | { success: false; error: string };
function fetchUser(id: number): Result<{ name: string }> { try { // Simulação de requisição if (id <= 0) { return { success: false, error: 'ID inválido' }; } return { success: true, data: { name: 'Ana' } }; } catch (error) { return { success: false, error: 'Erro de rede' }; }}
const result = fetchUser(1);if (result.success) { console.log('Usuário:', result.data.name);} else { console.error('Erro:', result.error);}O padrão Result permite evitar exceções implícitas e torna o tratamento de erros