Managing state in applications is fundamentally about tracking data that changes over time. When building interactive features like todo lists, shopping carts, or user profiles, you need to store data in memory and provide methods to create, read, update, and delete that data.
In TypeScript, classes provide an excellent way to encapsulate state management logic. By keeping data private and exposing controlled methods for manipulation, you create a clean interface that prevents external code from corrupting your state.
Arrays are perfect for managing collections of similar items. They provide built-in methods like push(), filter(), and find() that make common operations straightforward. The key is understanding when to mutate arrays directly versus creating new ones.
For unique identifiers, a simple counter pattern works well for in-memory data. Each new item gets the next sequential number, ensuring no duplicates. In real applications, you might use UUIDs or database-generated IDs instead.
When designing state management classes, think about the operations users need: adding items, removing items, updating items, and querying items. Each method should have a single responsibility and return meaningful values (like the created item or a boolean indicating success).
Error handling is crucial too. Instead of throwing errors for missing items, return false or empty arrays. This makes your API more predictable and easier to use in UI code where missing items are common.
The immutability principle suggests returning copies of internal data rather than direct references. This prevents external code from accidentally modifying your internal state, which could lead to bugs that are hard to track down.
1class BookLibrary {
2 private books: Book[] = [];
3 private nextId = 1;
4
5 addBook(title: string, author: string): Book {
6 const book = {
7 id: this.nextId++,
8 title,
9 author,
10 isCheckedOut: false
11 };
12 this.books.push(book);
13 return book;
14 }
15
16 checkOutBook(id: number): boolean {
17 const book = this.books.find(b => b.id === id);
18 if (book && !book.isCheckedOut) {
19 book.isCheckedOut = true;
20 return true;
21 }
22 return false;
23 }
24
25 getAvailableBooks(): Book[] {
26 return this.books.filter(b => !b.isCheckedOut);
27 }
28}