You handle errors with JavaScript's try and catch. Under strict, TypeScript types the caught value as unknown, because JavaScript can throw anything, not only Error objects. You narrow it before you use it.
function parseNumber(value: string): number {
try {
const parsed = parseInt(value);
if (isNaN(parsed)) {
throw new Error(`Invalid number: ${value}`);
}
return parsed;
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
throw error;
}
}
// Custom error types
class ValidationError extends Error {
constructor(
message: string,
public field: string,
public value: any
) {
super(message);
this.name = 'ValidationError';
}
}
The instanceof Error check narrows error, so error.message compiles. The useUnknownInCatchVariables option, part of strict, sets that default. Without it the variable is any, and the compiler checks nothing.
Custom error classes extend Error and add typed fields, like field and value on ValidationError. Setting name makes logs show which error it was. A caller can test err instanceof ValidationError and then read err.field safely.
TypeScript does not track which errors a function throws, so document them, or return a result type for failures callers must handle.
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓