@banksia/signals is built on five architectural principles engineered for predictability, maximum runtime throughput, and developer ergonomics.
State is accessed and mutated using standard JavaScript object and array syntax:
Why it matters: Developers should not have to learn custom accessor methods (state.user.name.get() / state.user.name.set('Bob')), action dispatchers, or reducer patterns for simple business mutations. Standard language idioms seamlessly bridge into the reactive graph.
return makeReactive(this))Domain stores and state machines remain pure, idiomatic TypeScript classes. There is no need for base classes, legacy experimental decorators, or build-step compiler transforms:
Why it matters: Returning makeReactive(this) in the constructor makes the class instance deeply reactive while retaining full prototype methods, getters, and instanceof fidelity. Your domain logic stays portable, testable, and completely decoupled from framework runtime dependencies.
Synchronous state mutations across multiple properties or collection items are automatically coalesced into a single microtask turn:
Why it matters: Unbatched reactive updates lead to "glitches" (transient intermediate calculations) and trigger catastrophic DOM layout thrashing. Automatic microtask batching provides transactional consistency by default, while flushBatch() remains available when immediate synchronous layout synchronization is required.
Native JavaScript collections wrapped with makeReactive distinguish between item reads, key mutations, and size changes:
Array: .push(), .pop(), .shift(), .unshift(), .splice(), .sort(), .reverse(), .length, and indexed mutations.Map: .set(), .get(), .has(), .delete(), .clear(), .keys(), .values(), .entries(), .size.Set: .add(), .has(), .delete(), .clear(), .keys(), .values(), .entries(), .size.Why it matters: Heavy applications rely heavily on Maps, Sets, and Arrays. Granular collection tracking prevents coarse-grained invalidation cascades, keeping data tables and memory registries lightning-fast.
Domain models are completely independent of UI presentation. The exact same domain store instance can drive a React component, a Lit Web Component, a SolidJS app, or a vanilla micro-frontend:
Why it matters: Enterprise applications frequently evolve, migrate frameworks, or embed micro-frontends with different UI stacks. Separating domain state into pure reactive models prevents framework lock-in and guarantees maximal code reuse.