TypeScript: Tratamento de erros no TypeScript
Última atualização: 2026-10-22
O tratamento de erros é uma parte essencial de qualquer projeto — o sistema de tipos do TypeScript torna o tratamento de erros mais seguro e previsível.
1. Noções básicas sobre o tratamento de erros em JavaScript
(1) try/catch/finally
TYPESCRIPT
try {
let data = JSON.parse(input);
console.log(data);
} catch (error) {
// error The type is unknown(strict In mode)
console.log("Parsing Failed");
} finally {
console.log("Free Up Resources");
// This will be executed regardless of success or failure
}
(2) instrução throw
O JavaScript pode lançar qualquer valor — não apenas objetos Error:
TYPESCRIPT
throw new Error("An error occurred"); // ✅ Standard Practice
throw "An error occurred"; // ⚠️ It's possible, but not ideal.
throw 404; // ⚠️ It's possible, but not ideal.
throw { code: 500, msg: "Server Error" }; // ⚠️ It's possible, but not ideal.
📌 Recomendação: Sempre lance um objeto
Error (ou uma de suas subclasses) — ele contém informações da pilha de chamadas, o que facilita a depuração. Lançar uma string ou um número não fornece informações da pilha de chamadas.
(3) Tipos de erros
TYPESCRIPT
interface Error {
name: string; // Error name (e.g., "TypeError", "RangeError")
message: string; // Error Description
stack?: string; // Call Stack(Non-standard but widely supported)
}
2. Tipos de erro embutidos e restrição de tipos
(1) Erros comuns de fábrica
| Tipo de erro | Causado por |
|---|---|
Error |
Erro geral |
TypeError |
Erro de digitação (por exemplo, null.toString()) |
RangeError |
Valor fora do intervalo (por exemplo, estouro recursivo) |
SyntaxError |
Erro de sintaxe (por exemplo, falha no JSON.parse) |
ReferenceError |
Referência a uma variável não definida |
URIError |
Erro de codificação/decodificação de URI |
(2) Reduzindo os tipos de erros com instanceof
TYPESCRIPT
function processValue(value: unknown) {
try {
let num = Number(value);
if (isNaN(num)) throw new TypeError("Not a valid number");
if (num < 0) throw new RangeError("Cannot be a negative number");
return num;
} catch (error) {
if (error instanceof TypeError) {
console.log(`Type error:${error.message}`); // ✅ narrowed to TypeError
} else if (error instanceof RangeError) {
console.log(`Range error:${error.message}`); // ✅ narrowed to RangeError
} else if (error instanceof Error) {
console.log(`Other Errors:${error.message}`); // ✅ narrowed to Error
} else {
// In theory, it won't reach there.——JavaScript Always throw Error or its subclasses
console.log("Unknown error");
}
}
}
3. Classes de erro personalizadas
(1) Erros personalizados básicos
TYPESCRIPT
class AppError extends Error {
constructor(message: string) {
super(message);
this.name = "AppError"; // Incorrect setting name
}
}
class ValidationError extends AppError {
constructor(
message: string,
public field: string // Additional error messages
) {
super(message);
this.name = "ValidationError";
}
}
class NotFoundError extends AppError {
constructor(
public resource: string,
public id: number | string
) {
super(`${resource} (${id}) Does not exist`);
this.name = "NotFoundError";
}
}
(2) Como usar erros personalizados
TYPESCRIPT
function findUser(id: number) {
if (id <= 0) {
throw new ValidationError("IDMust be a positive number", "id");
}
// Simulated Search
if (id > 100) {
throw new NotFoundError("User", id);
}
return { id, name: "User" + id };
}
try {
let user = findUser(999);
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Verification Failed:Field ${error.field},${error.message}`);
} else if (error instanceof NotFoundError) {
console.log(`Not found:${error.resource},ID=${error.id}`);
} else if (error instanceof Error) {
console.log(`Error:${error.message}`);
}
}
▶ Exemplo: Sistema de erros HTTP
TYPESCRIPT
class HttpError extends Error {
constructor(
public statusCode: number,
message: string
) {
super(message);
this.name = "HttpError";
}
}
class BadRequestError extends HttpError {
constructor(message: string) {
super(400, message);
this.name = "BadRequestError";
}
}
class UnauthorizedError extends HttpError {
constructor(message: string = "Unauthorized") {
super(401, message);
this.name = "UnauthorizedError";
}
}
class ForbiddenError extends HttpError {
constructor(message: string = "Access Denied") {
super(403, message);
this.name = "ForbiddenError";
}
}
class NotFoundError2 extends HttpError {
constructor(resource: string) {
super(404, `${resource} Does not exist`);
this.name = "NotFoundError";
}
}
// Usage
function handleRequest(path: string) {
if (!path.startsWith("/api/")) {
throw new BadRequestError("The path must begin with /api/ Introduction");
}
if (path === "/api/admin") {
throw new ForbiddenError();
}
return { data: "Response Data" };
}
try {
let result = handleRequest("/api/users");
console.log(result.data);
} catch (error) {
if (error instanceof HttpError) {
console.log(`HTTP ${error.statusCode}: ${error.message}`);
}
}
Saída:
TEXT
Response Data
4. Padrão de resultados
O problema com o try/catch é que “as exceções são implícitas” — a assinatura da função não indica que ela pode lançar uma exceção. O padrão Result torna os erros parte do valor de retorno:
(1) Definir o tipo de resultado
TYPESCRIPT
type Success<T> = { ok: true; value: T };
type Failure<E> = { ok: false; error: E };
type Result<T, E = Error> = Success<T> | Failure<E>;
(2) Criar resultado
TYPESCRIPT
function success<T>(value: T): Success<T> {
return { ok: true, value };
}
function failure<E>(error: E): Failure<E> {
return { ok: false, error };
}
(3) Usando Result em vez de try/catch
TYPESCRIPT
function divide(a: number, b: number): Result<number, string> {
if (b === 0) {
return failure("The divisor cannot be zero.");
}
return success(a / b);
}
let result1 = divide(10, 2);
let result2 = divide(10, 0);
if (result1.ok) {
console.log(result1.value); // 5 ✅
} else {
console.log(result1.error);
}
if (result2.ok) {
console.log(result2.value);
} else {
console.log(result2.error); // "The divisor cannot be zero." ✅
}
(4) Resultado: Métodos baseados em ferramentas
TYPESCRIPT
function tryCatch<T>(fn: () => T): Result<T, Error> {
try {
return success(fn());
} catch (error) {
return failure(error instanceof Error ? error : new Error(String(error)));
}
}
async function tryAsync<T>(fn: () => Promise<T>): Promise<Result<T, Error>> {
try {
return success(await fn());
} catch (error) {
return failure(error instanceof Error ? error : new Error(String(error)));
}
}
// Usage
let parseResult = tryCatch(() => JSON.parse('{"name":"Charlie"}'));
if (parseResult.ok) {
console.log(parseResult.value.name); // "Charlie"
}
5. Tratamento dos tipos de erro no bloco catch
(1) No modo estrito, o erro é desconhecido
TYPESCRIPT
try {
JSON.parse("invalid");
} catch (error) {
// error The type is unknown(TypeScript 4.4+)
// console.log(error.message); // ❌ unknown NonemessageProperties
// ✅ Method 1:instanceof Inspection
if (error instanceof Error) {
console.log(error.message);
}
// ✅ Method 2:Type Assertion(Caution)
let msg = (error as Error).message;
// ✅ Method 3:Type Guard Function
function getErrorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
if (typeof error === "string") return error;
return "Unknown error";
}
console.log(getErrorMessage(error));
}
(2) O tipo error em versões mais antigas do TypeScript
TYPESCRIPT
// TypeScript 4.3 and earlier——catch 's error The type is any
// You can tsconfig Useful useUnknownInCatchVariables: true Change to unknown
// TypeScript 4.4+——Default unknown(strict In mode)
▶ Exemplo: Estreitando tipos de erro unknown
Saída:
TEXT
Division by zero
TYPESCRIPT
function safeReadFile(path: string): string | null {
try {
let content = "[simulated file content]";
if (Math.random() > 0.5) throw new SyntaxError("Parse error");
return content;
} catch (error: unknown) {
if (error instanceof SyntaxError) {
console.log(`Syntax issue: ${error.message}`);
} else if (error instanceof Error) {
console.log(`Error: ${error.message}`);
} else {
console.log("Unknown error occurred");
}
return null;
}
}
let data = safeReadFile("config.json");
Saída:
TEXT
Division by zero
▶ Exemplo: Guarda de tipo para tratamento de erros
Saída:
TEXT
Division by zero
TYPESCRIPT
function isError(value: unknown): value is Error {
return value instanceof Error;
}
function getErrorMessage(error: unknown): string {
if (isError(error)) return error.message;
if (typeof error === "string") return error;
if (typeof error === "number") return `Error code: ${error}`;
return "An unknown error occurred";
}
type AppResult<T> = { ok: true; value: T } | { ok: false; error: string };
function divide(a: number, b: number): AppResult<number> {
if (b === 0) return { ok: false, error: "Division by zero" };
return { ok: true, value: a / b };
}
let r = divide(10, 0);
if (!r.ok) console.log(getErrorMessage(r.error)); // Division by zero
Saída:
TEXT
Division by zero
❓ Perguntas Frequentes
P O que devo usar,
try/catch ou o padrão Result?R As duas abordagens não são mutuamente exclusivas.
try/catch é o mecanismo padrão de tratamento de exceções em JavaScript/TypeScript — adequado para erros imprevisíveis em tempo de execução (como falhas de rede ou problemas de análise de JSON). O padrão Result é adequado para erros de negócio previsíveis — a assinatura da função declara explicitamente que “é possível ocorrer uma falha”, e quem chama a função deve lidar com ela. Basta manter um estilo consistente em todo o seu projeto.R Porque o JavaScript permite que qualquer valor seja lançado — tanto
throw "message" quanto throw 42 são válidos. O TypeScript não pode garantir que o valor capturado por catch seja uma instância de Error; portanto, usar unknown é a abordagem mais segura. No desenvolvimento prático, 99% dos erros lançados são objetos Error — você pode restringir a captura usando instanceof Error.P Uma classe de erro personalizada precisa chamar
super?R Sim, precisa. Quando uma classe de erro personalizada herda de
Error, ela deve chamar super(message) no construtor para inicializar a propriedade message de Error. Também é recomendável definir this.name manualmente — caso contrário, name assumirá por padrão o nome da classe pai.P O código no bloco
finally afeta o valor de retorno?R Uma instrução
return no bloco finally substitui a instrução return no bloco try/catch — essa é uma fonte comum de erros. Recomenda-se usar o bloco finally apenas para limpeza de recursos (fechar arquivos, liberar bloqueios etc.) e não incluir instruções return nesse bloco.📖 Resumo
- O sistema de erros embutido do JavaScript — Error, TypeError, RangeError e outras subclasses
- Use
instanceofno blococatchpara restringir o tipo de erro e acessar com segurança as propriedades de um erro específico - Crie uma classe de erro personalizada que herde de
Errore adicione propriedades específicas do negócio (comofieldestatusCode). - O padrão
Resulttorna os erros parte do valor de retorno — uma união distinguível deokeerror - O tipo de erro no bloco
catchéunknown— useinstanceofou guardas de tipo para lidar com isso com segurança - Sempre lance um objeto
Error; não lance strings nem números
📝 Exercícios
- Problema básico (Dificuldade ⭐): Escreva uma função
safeParse(json: string): Result<object, Error>que envolvaJSON.parseem um blocotry/catche retornesuccessem caso de sucesso efailureem caso de falha. - Problema avançado (Dificuldade ⭐⭐): Defina a classe base
AppErrore as subclassesDatabaseError(com uma propriedadequery) eAuthError(com uma propriedadestatusCode). Escreva uma função que retorne diferentes códigos de status HTTP e mensagens com base no tipo de erro. - Desafio (Dificuldade: ⭐⭐⭐): Implemente
tryAsync<T>(fn: () => Promise<T>): Promise<Result<T, AppError>>para converter uniformemente as exceções de operações assíncronas no sistema AppError (distinguindo entre erros de rede, erros de tempo limite e erros de servidor). Escreva uma funçãofetchWithRetryque tente novamente automaticamente em caso de falha.