Exceptions are unexpected events that occur during the execution of a program, disrupting the normal flow of the code. In TypeScript, exceptions are typically represented as objects of a specific type. When an exceptional situation arises, an exception is thrown, and the normal execution of the program is halted until the exception is caught and handled.
TypeScript inherits several built - in exception types from JavaScript. Some of the most common ones are:
Error
: This is the base class for all exceptions in JavaScript and TypeScript. It has a message
property that provides a human - readable description of the error.SyntaxError
: Thrown when there is a syntax error in the code, such as an incorrect use of language grammar.ReferenceError
: Occurs when an attempt is made to reference an undeclared variable.TypeError
: Thrown when an operation is performed on an object of an inappropriate type.In addition to the built - in exception types, TypeScript allows developers to create custom exception types. Custom exception types can provide more specific information about the error and make the code more self - explanatory. To create a custom exception type, we can extend the Error
class.
class MyCustomError extends Error {
constructor(message: string) {
super(message);
this.name = 'MyCustomError';
}
}
To throw an exception in TypeScript, we use the throw
keyword. We can throw either a built - in exception type or a custom exception type.
function divide(a: number, b: number): number {
if (b === 0) {
throw new Error('Division by zero is not allowed');
}
return a / b;
}
try {
const result = divide(10, 0);
console.log(result);
} catch (error) {
console.error(error.message);
}
We use the try...catch
block to catch and handle exceptions. The code that might throw an exception is placed inside the try
block, and the code to handle the exception is placed inside the catch
block.
try {
const data = JSON.parse('invalid json');
console.log(data);
} catch (error) {
if (error instanceof SyntaxError) {
console.error('There was a syntax error in the JSON data:', error.message);
} else {
console.error('An unknown error occurred:', error);
}
}
The finally
block is optional and is always executed, regardless of whether an exception was thrown or not. It is often used to release resources, such as closing files or network connections.
function readFile() {
try {
// Code to read a file
console.log('Reading file...');
throw new Error('File not found');
} catch (error) {
console.error('Error reading file:', error.message);
} finally {
console.log('Closing file resources...');
}
}
readFile();
In larger applications, it is a good practice to have a centralized error - handling mechanism. This can be achieved by creating a global error handler that catches all unhandled exceptions.
window.onerror = function (message, source, lineno, colno, error) {
console.error('Global error caught:', message, error);
return true;
};
function faultyFunction() {
throw new Error('Something went wrong in the faulty function');
}
faultyFunction();
Logging exceptions is crucial for debugging and monitoring the application. We can log the exception message, stack trace, and other relevant information.
function doSomethingRisky() {
try {
// Risky code
throw new MyCustomError('This is a custom error');
} catch (error) {
console.error('Caught an exception:', error.message, error.stack);
}
}
doSomethingRisky();
Use custom exception types whenever possible to provide more detailed information about the error. This makes it easier to debug and handle different types of errors.
class DatabaseConnectionError extends Error {
constructor(message: string) {
super(message);
this.name = 'DatabaseConnectionError';
}
}
function connectToDatabase() {
// Simulate a database connection failure
throw new DatabaseConnectionError('Could not connect to the database');
}
try {
connectToDatabase();
} catch (error) {
if (error instanceof DatabaseConnectionError) {
console.error('Database connection error:', error.message);
}
}
Catching generic Error
types can hide potential bugs in the code. Instead, be more specific and catch only the exceptions that you expect and know how to handle.
try {
const data = JSON.parse('{"key": "value"}');
console.log(data);
} catch (error) {
if (error instanceof SyntaxError) {
console.error('Syntax error in JSON data:', error.message);
} else {
throw error; // Re - throw the error if it's not a SyntaxError
}
}
Exception handling in TypeScript is an essential part of writing robust and reliable code. By understanding the fundamental concepts, usage methods, common practices, and best practices, developers can effectively manage errors and ensure that their applications can handle unexpected situations gracefully. Custom exception types, proper use of try...catch
blocks, and centralized error handling are some of the key techniques that can enhance the quality of the code.