ilokesto

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.

On this page