immer

Write methods (and set calls) as Immer draft mutations instead of returning new state objects.

Basic usage

import { createStore } from "@kintools/store-core";
import { immer } from "@kintools/store-plugins";
 
const store = createStore({ count: 0, items: [] as string[] }).use(
  immer({
    increment(amount: number): void {
      this.set((draft) => {
        draft.count += amount;
      });
    },
    addItem(item: string): void {
      this.set((draft) => {
        draft.items.push(item);
      });
    },
    reset(): void {
      this.set((draft) => {
        draft.count = 0;
        draft.items = [];
      });
    },
  }),
);
 
store.increment(5);
store.addItem("hello");
store.reset();

immer(plugin) wraps a plugin written against an ImmerStore, identical to a normal store except set accepts a recipe (draft) => void instead of a full state replacement, and returns a standard StorePlugin ready for store.use(). Every method (and onActivated/onDestroy) is individually wrapped so this resolves to the Immer-flavored store no matter how it's reached: externally, or via a sibling/earlier-plugin call through this.

With namespacing

immer can also be applied as a namespaced plugin:

const store = createStore({ todos: [] as string[] }).use(
  "todos",
  immer({
    add(text: string): void {
      this.set((draft) => {
        draft.todos.push(text);
      });
    },
    clear(): void {
      this.set((draft) => {
        draft.todos = [];
      });
    },
  }),
);
 
store.todos.add("hello");
store.todos.clear();

Note on type inference

Because Immer mutates a draft in-place (void return), methods written with immer do not need to return a value. TypeScript fully infers argument types from the method signature.