Using IndexedDB with TypeScript: Practical Examples

Updated: February 14, 2024 By: Guest Contributor Post a comment

Introduction

An effective application often requires a robust way of managing data. When operating in the browser, one of the most powerful storage solutions available is IndexedDB. This article dives into how we can leverage IndexedDB within a TypeScript project, offering type safety and enhancing developer experience through practical examples.

Getting Started with IndexedDB and TypeScript

Before diving into the code, it’s essential to understand what IndexedDB is. It’s a low-level API for client-side storage of significant amounts of structured data, including files/blobs. This makes it exceptionally useful for web applications that need to store data on the client side.

Using IndexedDB with TypeScript enhances type safety and improves the developer experience. However, direct interactions with IndexedDB can be verbose and complex due to its asynchronous nature. Fortunately, TypeScript can make these interactions more manageable.

First, you’ll need to ensure your environment is set up correctly. This setup includes having TypeScript installed and your desired development tools ready. Once set, let’s dive into our first basic example.

Example 1: Opening a Database

Our journey with IndexedDB and TypeScript begins with opening or creating a database. Here is a basic example:

const openRequest = indexedDB.open('MyDatabase', 1);

openRequest.onupgradeneeded = function(e) {
  const db = openRequest.result;
  if (!db.objectStoreNames.contains('books')) {
    db.createObjectStore('books', { keyPath: 'id' });
  }
};

openRequest.onsuccess = function(e) {
  console.log('Database opened successfully');
};

openRequest.onerror = function(e) {
  console.error('Error opening database', openRequest.error);
};

This simple code snippet uses the indexedDB.open method to open a database. If the specified version of the database doesn’t exist, it triggers an onupgradeneeded event where we define our initial store.

Advanced Interactions with IndexedDB

After successfully opening a database, the next step typically involves creating, reading, updating, and deleting (CRUD) operations. The following examples dive deeper into these operations, employing TypeScript for better structure and readability.

Example 2: Adding and Retrieving Data

Adding data to our database involves creating a transaction, then using it to perform operations such as adding or retrieving data. Here’s a closer look:

function addBook(db: IDBDatabase) {
  const transaction = db.transaction('books', 'readwrite');
  const store = transaction.objectStore('books');
  const book = { id: '1', title: 'TypeScript Essentials', author: 'Jane Doe' };
  const request = store.add(book);

  request.onsuccess = function() {
    console.log('Book added to the database');
  };
  request.onerror = function() {
    console.error('Error adding book to the database', request.error);
  };
}

This function demonstrates how to add data to an IndexedDB store and confirm its success or failure. It is a basic operation that sets the stage for more complex interactions.

Example 3: Complex Queries and Transactions

The final example covers executing more complex queries and managing transactions. This involves creating indices, performing range queries, and using cursors to iterate over data.

function fetchBooksByAuthor(db: IDBDatabase, author: string) {
  const transaction = db.transaction('books', 'readonly');
  const store = transaction.objectStore('books');
  const index = store.index('by_author');
  const request = index.openCursor(IDBKeyRange.only(author));

  request.onsuccess = function() {
    const cursor = request.result;
    if (cursor) {
      console.log('Book:', cursor.value);
      cursor.continue();
    } else {
      console.log('No more books by this author');
    }
  };
}

This advanced example shows how to use an index to fetch data based on specific attributes, in this case, the author of a book. This example demonstrates querying capabilities and navigating through data sets.

Conclusion

IndexedDB provides a potent solution for client-side storage in web applications, and when used in conjunction with TypeScript, it offers a type-safe and developers-friendly way of handling data. Through the examples provided, we’ve seen how to open databases, perform CRUD operations, and execute complex queries. While IndexedDB’s API can be verbose and somewhat low-level, TypeScript helps manage this complexity, making it a powerful combination for web development.