TypeScript: Tratamento de erros no TypeScript
Última atualização: 2026-08-26
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
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:
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.
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
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
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
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
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
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:
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
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
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
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
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
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 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:
Division by zero
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:
Division by zero
▶ Exemplo: Guarda de tipo para tratamento de erros
Saída:
Division by zero
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:
Division by zero
❓ Perguntas Frequentes
P: O que devo usar,
try/catchou 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.
P: Por que o erro é interceptado por
catchunknownem vez deError? R: Porque o JavaScript permite que qualquer valor seja lançado — tantothrow "message"quantothrow 42são válidos. O TypeScript não pode garantir que o valor capturado porcatchseja uma instância deError; portanto, usarunknowné a abordagem mais segura. No desenvolvimento prático, 99% dos erros lançados são objetos Error — você pode restringir a captura usandoinstanceof Error.
P: Uma classe de erro personalizada precisa chamar
super? R: Sim, precisa. Quando uma classe de erro personalizada herda deError, ela deve chamarsuper(message)no construtor para inicializar a propriedademessagedeError. Também é recomendável definirthis.namemanualmente — caso contrário,nameassumirá por padrão o nome da classe pai.
P: O código no bloco
finallyafeta o valor de retorno? R: Uma instruçãoreturnno blocofinallysubstitui a instruçãoreturnno blocotry/catch— essa é uma fonte comum de erros. Recomenda-se usar o blocofinallyapenas para limpeza de recursos (fechar arquivos, liberar bloqueios etc.) e não incluir instruçõesreturnnesse 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.