Store class
Store<T> is the concrete public class exported by @ilokesto/store. The package also exports a createStore() factory and structural ReadableStore<T> / StoreApi<T> contracts.
import { Store } from "@ilokesto/store";
const store = new Store({ ready: false });Constructor
new Store<T>(initialState: T)The constructor saves initialState as both the first current state and the value returned by getInitialState().
No clone is made. If you pass an object, keep ownership discipline: treat the object as immutable after giving it to the store.
getState()
getState(): Readonly<T>Returns the current state synchronously. The Readonly<T> type discourages direct assignment through the returned value, but it does not create a runtime freeze and it is shallow from TypeScript's point of view.
const state = store.getState();
console.log(state.ready);Use getState():
- before deriving an immediate value,
- inside a
subscribe()listener, - inside adapter code that needs to render the latest snapshot.
Do not use it as a reason to mutate state in place.
getInitialState()
getInitialState(): Readonly<T>Returns the exact initial value captured by the constructor.
const initial = store.getInitialState();getInitialState() does not reset the store. To reset, pass the initial value back through setState() yourself:
store.setState(store.getInitialState());If the current state is already the same reference as the initial state, Object.is prevents notification. If you need subscribers to react to a reset of object state, pass a fresh object with the same fields.
Factory and structural contracts
createStore(initialState) creates a fresh concrete Store<T>. It never detects or reuses a store-shaped value.
import { createStore, type ReadableStore, type StoreApi } from "@ilokesto/store";
const counter = createStore({ count: 0 });
const reader: ReadableStore<{ count: number }> = counter;
const writer: StoreApi<{ count: number }> = counter;Use ReadableStore<T> when a consumer only needs reads and subscriptions. Use StoreApi<T> when it also needs writes and middleware registration. These structural interfaces are useful for adapters; applications that need the built-in implementation can keep using Store<T>.
set(value) provides unambiguous replacement and update(updater) provides explicit computation. This distinction matters when T itself is a function; setState(fn) retains its updater meaning. All three write paths use the same middleware pipeline.
Public API summary
Store<T>: owns one state value.getState(): reads the current value.getInitialState(): reads the constructor value.setState(): replaces the value or computes it with an updater after middleware.subscribe(): registers a listener and returns cleanup.pushMiddleware()/unshiftMiddleware(): compose update middleware.createStore(): creates a fresh concrete store.ReadableStore<T>/StoreApi<T>: structural read-only and writable contracts.set()/update(): explicit replacement and computation.subscribeSelector(): subscribes to a derived selection.
Continue to setState for replacement and error behavior, or subscribe for subscription ownership and selector delivery.