Exercise: Building a Generic Data Store

Build a flexible, type-safe, and reusable DataStore class using generics, constraints, and composition techniques.

We'll cover the following...

In this challenge, we’re going to put everything from this chapter into action: classes, generics, constraints, method typing, and reusable patterns.

The goal is to implement a class called DataStore<T> that can safely store, retrieve, and manage typed items by ID. We’ll support optional item transformation at insertion time. We’ll also build a subclass to prevent mutation, and demonstrate all usage patterns with clear test code.

Requirements

Implement the following:

  1. There should be a generic class DataStore<T> where T must have an id: string property.

  2. Store items in a Record<string, T>.

  3. Add the following methods:

    1. addItem(id: string, item: T): void

    2. removeItem(id: string): boolean

    3. getItem(id: string): T | undefined

  4. Support an optional transformer function (item: T) => T passed via constructor.

    1. This function should preprocess items before they’re stored.

  5. Add a static method fromArray<U>(items: U[], transformer?: (item: U) => U): DataStore<U> for bulk creation.

  6. Create a ReadonlyStore<T> subclass that throws an error when addItem or removeItem is called.

Good luck!