Type-Safe Error Handling
JavaScript catch blocks give you 'unknown' errors. TypeScript provides tools to handle errors safely — custom error classes, the Result pattern, type guards for errors, and runtime validation libraries like Zod.
40 min•By Priygop Team•Last updated: Feb 2026
Error Handling Patterns
Example
// Problem: catch gives you 'unknown'
try {
const data = JSON.parse(input);
} catch (error) {
// error is 'unknown' — must narrow before using
if (error instanceof SyntaxError) {
console.log(error.message); // Now TypeScript knows it's SyntaxError
} else if (error instanceof Error) {
console.log(error.message);
} else {
console.log("Unknown error:", String(error));
}
}
// Custom error classes
class HttpError extends Error {
constructor(
public statusCode: number,
message: string,
public details?: Record<string, string>
) {
super(message);
this.name = "HttpError";
}
}
class ValidationError extends Error {
constructor(
public field: string,
message: string
) {
super(message);
this.name = "ValidationError";
}
}
// Type guard for errors
function isHttpError(error: unknown): error is HttpError {
return error instanceof HttpError;
}
// Result pattern (no exceptions)
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
function divide(a: number, b: number): Result<number, string> {
if (b === 0) {
return { ok: false, error: "Division by zero" };
}
return { ok: true, value: a / b };
}
const result = divide(10, 0);
if (result.ok) {
console.log(result.value); // TypeScript knows: number
} else {
console.log(result.error); // TypeScript knows: string
}
// Async Result pattern
async function fetchUser(id: number): Promise<Result<User>> {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
return { ok: false, error: new Error(`HTTP ${res.status}`) };
}
const user = await res.json();
return { ok: true, value: user };
} catch (error) {
return { ok: false, error: error instanceof Error ? error : new Error(String(error)) };
}
}