How to Use Try Catch in TypeScript

Use try/catch in TypeScript when code may throw runtime errors or reject promises, and the app needs graceful fallback behavior instead of crashing. This is perfect for API calls, JSON parsing, file operations, and risky user input.

What you’ll build or solve

You’ll learn how to use try/catch in TypeScript with synchronous code, async/await flows, and typed error narrowing. You’ll also know how to safely inspect unknown errors.

When this approach works best

This approach is the right choice when failures are expected and recoverable.

Common real-world scenarios include:

  • API request failures
  • JSON parsing
  • Local storage reads
  • User input parsing
  • File access

This is a bad idea when errors should intentionally bubble up to a higher-level boundary instead of being silently swallowed.

Prerequisites

You only need:

  • Basic TypeScript syntax
  • Familiarity with async/await
  • Understanding of runtime errors

Step-by-step instructions

Step 1: Wrap risky code in try

The try block contains code that may fail.

try {
  const data = JSON.parse('{"name":"Alex"}');
  console.log(data.name);
} catch (error) {
  console.error("Invalid JSON");
}

This prevents invalid input from crashing the app.

Step 2: Narrow the error safely

In TypeScript, catch errors are often unknown.

try {
  throw new Error("Failed");
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message);
  }
}

This is the safest way to access error properties.

Step 3: Use try/catch with async code

This is the cleanest async error pattern.

async function loadUser(): Promise<void> {
  try {
    const response = await fetch("/api/user");
    const user = await response.json();
    console.log(user);
  } catch (error) {
    console.error("Failed to load user");
  }
}

This keeps async flows readable and safe.

Step 4: Use finally for cleanup

Cleanup logic belongs in finally.

try {
  console.log("Loading...");
} catch {
  console.log("Failed");
} finally {
  console.log("Done");
}

This runs whether the operation succeeds or fails.

What to look for:

  • Put risky logic inside try
  • Handle recoverable failures in catch
  • Narrow errors with instanceof Error
  • Use finally for cleanup
  • Great for async workflows

Examples you can copy

JSON parse

try {
  JSON.parse(value);
} catch {}

API fetch

try {
  await fetch("/api/users");
} catch {}

Error narrowing

if (error instanceof Error)

Common mistakes and how to fix them

Mistake 1: Accessing error.message directly

What the reader might do:

catch (error) {
  console.log(error.message);
}

Why it breaks: error may be unknown.

Corrected approach:

Use instanceof Error.

Mistake 2: Swallowing errors silently

What the reader might do:

catch {}

Why it breaks: debugging becomes much harder.

Corrected approach:

Log, recover, or rethrow intentionally.

Mistake 3: Using try/catch around non-throwing async chains

What the reader might do:

Wrap promise chains without await.

Why it breaks: rejected promises may bypass the catch block.

Corrected approach:

Use await or .catch().

Troubleshooting

If error properties fail, narrow the error type.

If async failures escape, make sure the promise is awaited.

If bugs disappear silently, stop using empty catches.

If cleanup must always run, move it into finally.

Quick recap

  • Use try for risky code
  • Handle failures in catch
  • Narrow errors safely
  • Use finally for cleanup
  • Await promises inside try