try / catch Error Handling & catch Narrowing

Last updated: 2026-10-22

try / catch Error Handling & catch Narrowing

TypeScript error handling has two pain points: the catch variable is unknown under strict mode (JS can throw anything, so the compiler dare not assume Error), requiring narrowing before you can touch .message; and "this may throw" is invisible in type signatures. The fixes: narrow unknown with instanceof, and for expected failures use the Result pattern, encoding success/failure right in the return type.

GroupEngineering & Practice
KindSyntax
Strict modeNot required

ℹ️ Info The editor transpiles TypeScript to JavaScript and runs it (no type checking); see each example's Output for type-check results.

📝 Syntax

// 1) Narrowing unknown
try {
  risky();
} catch (err: unknown) {
  if (err instanceof Error) console.log(err.message);
  else console.log("unknown throw:", err);
}

// 2) Result pattern: a union type encoding success or failure
type Result<T> = { ok: true; value: T } | { ok: false; error: string };

function attempt<T>(fn: () => T): Result<T> {
  try { return { ok: true, value: fn() }; }
  catch { return { ok: false, error: "failed" }; }
}

⚙️ Parameters

unknownThe catch variable's type (the default under strict mode): it can hold anything, but must be narrowed before use — that is where the safety comes from
instanceofThe most common narrowing tool: after err instanceof Error you get .message/.stack; works with custom error classes too
Result<T>A hand-rolled return type: { ok: true; value: T } | { ok: false; error }. Callers must check ok first; each branch exposes only value or error

Returns:The Result pattern's return type is a discriminated union: value exists only when ok is true, error only when false — possible failure is encoded in the type, and callers cannot compile without handling the failure branch.

▶ Example

Edit the code below and click Try it to see the transpiled result:

Output:

caught RangeError: not a positive integer: abc
7 0
{"ok":true,"value":42}
failed: invalid input

(Runtime output after transpilation; .message is only reachable after instanceof narrowing — touching err.message without it yields error TS18046)

💡 Notes

ℹ️ Info JS lets you throw anything (numbers, strings, objects), so TS types the catch variable as unknown instead of Error — a protection from useUnknownInCatchVariables (included in strict) that stops you counting on a .message property that may not exist.
💡 Tip instanceof is not the only tool: typeof err === "string", "message" in err and custom type guards like isApiError(err) all work; keep a final fallback branch so any thrown value is covered.
⚠️ Note The Result pattern makes call sites longer (every call must check ok). A common compromise: keep exceptions in the core flow, convert to Result at boundaries (parsing user input, external APIs), leaving expected failures to explicit handling.
More cases coming soon.

📚 Related tutorials

❓ FAQ

Q Why can't I use err.message directly in catch?
A Because err is unknown (JS can throw anything, including strings), the compiler cannot guarantee .message exists. Narrow first — err instanceof Error, typeof err === "string" or "message" in err — then access it safely.
Q How do I narrow custom error classes?
A Define your own class extending Error (e.g. ValidationError), then narrow with err instanceof ValidationError to reach custom fields like err.field. Use multiple narrowing branches in one try, ordered from specific to general.
Q When should I throw versus return a Result?
A Exceptions suit unexpected situations (bugs, sudden network loss) that callers mostly should not handle; Results suit expected failures (input parsing, form validation) that callers must handle — the type forces them. The test: does the caller have a meaningful next step after this failure?
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏