typescript / intermediate
Snippet
Constructing a Type-Safe Micro State Store with Subscriptions
Centralized state management frameworks rely on predictable state mutations and reactive subscriptions. Combining `Readonly<T>`, `Partial<T>`, and `Object.freeze`, this micro store ensures state immutability and subscriber notification guarantees.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
type Listener<S> = (state: Readonly<S>) => void;class Store<S extends object> {private state: S;private listeners = new Set<Listener<S>>();constructor(initialState: S) {this.state = Object.freeze({ ...initialState });}getState(): Readonly<S> {return this.state;}setState(updater: Partial<S> | ((prevState: Readonly<S>) => Partial<S>)): void {const changes = typeof updater === "function" ? updater(this.state) : updater;this.state = Object.freeze({ ...this.state, ...changes });this.listeners.forEach((listener) => listener(this.state));}subscribe(listener: Listener<S>): () => void {this.listeners.add(listener);return () => this.listeners.delete(listener);}}interface CounterState {count: number;lastUpdated: string;}const store = new Store<CounterState>({ count: 0, lastUpdated: "never" });const unsubscribe = store.subscribe((state) => console.log(`Count: ${state.count}`));store.setState({ count: 1, lastUpdated: "now" });unsubscribe();
Breakdown
1
type Listener<S> = (state: Readonly<S>) => void;
Prevents state consumers from directly mutating internal store state through Readonly wrappers.
2
setState(updater: Partial<S> | ((prevState: Readonly<S>) => Partial<S>)): void
Supports functional state updates or partial state objects while updating internal reference safely.
3
subscribe(listener: Listener<S>): () => void
Registers reactive observers and returns a cleanup unsubscriber function.