@tanstack/store 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const derived = require("./derived.cjs");
4
4
  const effect = require("./effect.cjs");
5
5
  const store = require("./store.cjs");
6
+ const types = require("./types.cjs");
6
7
  const scheduler = require("./scheduler.cjs");
7
8
  exports.Derived = derived.Derived;
8
9
  exports.Effect = effect.Effect;
9
10
  exports.Store = store.Store;
11
+ exports.isUpdaterFunction = types.isUpdaterFunction;
10
12
  exports.__depsThatHaveWrittenThisTick = scheduler.__depsThatHaveWrittenThisTick;
11
13
  exports.__derivedToStore = scheduler.__derivedToStore;
12
14
  exports.__flush = scheduler.__flush;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const scheduler = require("./scheduler.cjs");
4
+ const types = require("./types.cjs");
4
5
  class Store {
5
6
  constructor(initialState, options) {
6
7
  this.listeners = /* @__PURE__ */ new Set();
@@ -13,17 +14,25 @@ class Store {
13
14
  unsub == null ? void 0 : unsub();
14
15
  };
15
16
  };
16
- this.setState = (updater) => {
17
- var _a, _b, _c;
18
- this.prevState = this.state;
19
- this.state = ((_a = this.options) == null ? void 0 : _a.updateFn) ? this.options.updateFn(this.prevState)(updater) : updater(this.prevState);
20
- (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b);
21
- scheduler.__flush(this);
22
- };
23
17
  this.prevState = initialState;
24
18
  this.state = initialState;
25
19
  this.options = options;
26
20
  }
21
+ setState(updater) {
22
+ var _a, _b, _c;
23
+ this.prevState = this.state;
24
+ if ((_a = this.options) == null ? void 0 : _a.updateFn) {
25
+ this.state = this.options.updateFn(this.prevState)(updater);
26
+ } else {
27
+ if (types.isUpdaterFunction(updater)) {
28
+ this.state = updater(this.prevState);
29
+ } else {
30
+ this.state = updater;
31
+ }
32
+ }
33
+ (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b);
34
+ scheduler.__flush(this);
35
+ }
27
36
  }
28
37
  exports.Store = Store;
29
38
  //# sourceMappingURL=store.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.cjs","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport type { AnyUpdater, Listener } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n setState = (updater: TUpdater) => {\n this.prevState = this.state\n this.state = this.options?.updateFn\n ? this.options.updateFn(this.prevState)(updater)\n : (updater as any)(this.prevState)\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":["__flush"],"mappings":";;;AA0BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAsB;AAWtC,SAAA,YAAY,CAAC,aAA+B;;AACrC,WAAA,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACN,aAAA,UAAU,OAAO,QAAQ;AACtB;AAAA,MACV;AAAA,IACF;AAEA,SAAA,WAAW,CAAC,YAAsB;;AAChC,WAAK,YAAY,KAAK;AACtB,WAAK,UAAQ,UAAK,YAAL,mBAAc,YACvB,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAO,IAC5C,QAAgB,KAAK,SAAS;AAGnC,uBAAK,YAAL,mBAAc,aAAd;AAGAA,gBAAAA,QAAQ,IAAa;AAAA,IACvB;AAzBE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EAAA;AAwBnB;;"}
1
+ {"version":3,"file":"store.cjs","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport { isUpdaterFunction } from './types'\nimport type { AnyUpdater, Listener, Updater } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n /**\n * Update the store state safely with improved type checking\n */\n setState(updater: (prevState: TState) => TState): void\n setState(updater: TState): void\n setState(updater: TUpdater): void\n setState(updater: Updater<TState> | TUpdater): void {\n this.prevState = this.state\n\n if (this.options?.updateFn) {\n this.state = this.options.updateFn(this.prevState)(updater as TUpdater)\n } else {\n if (isUpdaterFunction(updater)) {\n this.state = updater(this.prevState)\n } else {\n this.state = updater as TState\n }\n }\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":["isUpdaterFunction","__flush"],"mappings":";;;;AA2BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAsB;AAWtC,SAAA,YAAY,CAAC,aAA+B;;AACrC,WAAA,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACN,aAAA,UAAU,OAAO,QAAQ;AACtB;AAAA,MACV;AAAA,IACF;AAZE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EAAA;AAAA,EAkBjB,SAAS,SAA2C;;AAClD,SAAK,YAAY,KAAK;AAElB,SAAA,UAAK,YAAL,mBAAc,UAAU;AAC1B,WAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAmB;AAAA,IAAA,OACjE;AACD,UAAAA,MAAAA,kBAAkB,OAAO,GAAG;AACzB,aAAA,QAAQ,QAAQ,KAAK,SAAS;AAAA,MAAA,OAC9B;AACL,aAAK,QAAQ;AAAA,MAAA;AAAA,IACf;AAIF,qBAAK,YAAL,mBAAc,aAAd;AAGAC,cAAAA,QAAQ,IAAa;AAAA,EAAA;AAEzB;;"}
@@ -22,5 +22,10 @@ export declare class Store<TState, TUpdater extends AnyUpdater = (cb: TState) =>
22
22
  options?: StoreOptions<TState, TUpdater>;
23
23
  constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>);
24
24
  subscribe: (listener: Listener<TState>) => () => void;
25
- setState: (updater: TUpdater) => void;
25
+ /**
26
+ * Update the store state safely with improved type checking
27
+ */
28
+ setState(updater: (prevState: TState) => TState): void;
29
+ setState(updater: TState): void;
30
+ setState(updater: TUpdater): void;
26
31
  }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function isUpdaterFunction(updater) {
4
+ return typeof updater === "function";
5
+ }
6
+ exports.isUpdaterFunction = isUpdaterFunction;
7
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sources":["../../src/types.ts"],"sourcesContent":["/**\n * @private\n */\nexport type AnyUpdater = (prev: any) => any\n\n/**\n * Type-safe updater that can be either a function or direct value\n */\nexport type Updater<T> = ((prev: T) => T) | T\n\n/**\n * @private\n */\nexport interface ListenerValue<T> {\n prevVal: T\n currentVal: T\n}\n\n/**\n * @private\n */\nexport type Listener<T> = (value: ListenerValue<T>) => void\n\n/**\n * Type guard to check if updater is a function\n */\nexport function isUpdaterFunction<T>(\n updater: Updater<T>,\n): updater is (prev: T) => T {\n return typeof updater === 'function'\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,kBACd,SAC2B;AAC3B,SAAO,OAAO,YAAY;AAC5B;;"}
@@ -2,6 +2,10 @@
2
2
  * @private
3
3
  */
4
4
  export type AnyUpdater = (prev: any) => any;
5
+ /**
6
+ * Type-safe updater that can be either a function or direct value
7
+ */
8
+ export type Updater<T> = ((prev: T) => T) | T;
5
9
  /**
6
10
  * @private
7
11
  */
@@ -13,3 +17,7 @@ export interface ListenerValue<T> {
13
17
  * @private
14
18
  */
15
19
  export type Listener<T> = (value: ListenerValue<T>) => void;
20
+ /**
21
+ * Type guard to check if updater is a function
22
+ */
23
+ export declare function isUpdaterFunction<T>(updater: Updater<T>): updater is (prev: T) => T;
package/dist/esm/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Derived } from "./derived.js";
2
2
  import { Effect } from "./effect.js";
3
3
  import { Store } from "./store.js";
4
+ import { isUpdaterFunction } from "./types.js";
4
5
  import { __depsThatHaveWrittenThisTick, __derivedToStore, __flush, __storeToDerived, batch } from "./scheduler.js";
5
6
  export {
6
7
  Derived,
@@ -10,6 +11,7 @@ export {
10
11
  __derivedToStore,
11
12
  __flush,
12
13
  __storeToDerived,
13
- batch
14
+ batch,
15
+ isUpdaterFunction
14
16
  };
15
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
@@ -22,5 +22,10 @@ export declare class Store<TState, TUpdater extends AnyUpdater = (cb: TState) =>
22
22
  options?: StoreOptions<TState, TUpdater>;
23
23
  constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>);
24
24
  subscribe: (listener: Listener<TState>) => () => void;
25
- setState: (updater: TUpdater) => void;
25
+ /**
26
+ * Update the store state safely with improved type checking
27
+ */
28
+ setState(updater: (prevState: TState) => TState): void;
29
+ setState(updater: TState): void;
30
+ setState(updater: TUpdater): void;
26
31
  }
package/dist/esm/store.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { __flush } from "./scheduler.js";
2
+ import { isUpdaterFunction } from "./types.js";
2
3
  class Store {
3
4
  constructor(initialState, options) {
4
5
  this.listeners = /* @__PURE__ */ new Set();
@@ -11,17 +12,25 @@ class Store {
11
12
  unsub == null ? void 0 : unsub();
12
13
  };
13
14
  };
14
- this.setState = (updater) => {
15
- var _a, _b, _c;
16
- this.prevState = this.state;
17
- this.state = ((_a = this.options) == null ? void 0 : _a.updateFn) ? this.options.updateFn(this.prevState)(updater) : updater(this.prevState);
18
- (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b);
19
- __flush(this);
20
- };
21
15
  this.prevState = initialState;
22
16
  this.state = initialState;
23
17
  this.options = options;
24
18
  }
19
+ setState(updater) {
20
+ var _a, _b, _c;
21
+ this.prevState = this.state;
22
+ if ((_a = this.options) == null ? void 0 : _a.updateFn) {
23
+ this.state = this.options.updateFn(this.prevState)(updater);
24
+ } else {
25
+ if (isUpdaterFunction(updater)) {
26
+ this.state = updater(this.prevState);
27
+ } else {
28
+ this.state = updater;
29
+ }
30
+ }
31
+ (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b);
32
+ __flush(this);
33
+ }
25
34
  }
26
35
  export {
27
36
  Store
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport type { AnyUpdater, Listener } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n setState = (updater: TUpdater) => {\n this.prevState = this.state\n this.state = this.options?.updateFn\n ? this.options.updateFn(this.prevState)(updater)\n : (updater as any)(this.prevState)\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":[],"mappings":";AA0BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAsB;AAWtC,SAAA,YAAY,CAAC,aAA+B;;AACrC,WAAA,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACN,aAAA,UAAU,OAAO,QAAQ;AACtB;AAAA,MACV;AAAA,IACF;AAEA,SAAA,WAAW,CAAC,YAAsB;;AAChC,WAAK,YAAY,KAAK;AACtB,WAAK,UAAQ,UAAK,YAAL,mBAAc,YACvB,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAO,IAC5C,QAAgB,KAAK,SAAS;AAGnC,uBAAK,YAAL,mBAAc,aAAd;AAGA,cAAQ,IAAa;AAAA,IACvB;AAzBE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EAAA;AAwBnB;"}
1
+ {"version":3,"file":"store.js","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport { isUpdaterFunction } from './types'\nimport type { AnyUpdater, Listener, Updater } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n /**\n * Update the store state safely with improved type checking\n */\n setState(updater: (prevState: TState) => TState): void\n setState(updater: TState): void\n setState(updater: TUpdater): void\n setState(updater: Updater<TState> | TUpdater): void {\n this.prevState = this.state\n\n if (this.options?.updateFn) {\n this.state = this.options.updateFn(this.prevState)(updater as TUpdater)\n } else {\n if (isUpdaterFunction(updater)) {\n this.state = updater(this.prevState)\n } else {\n this.state = updater as TState\n }\n }\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":[],"mappings":";;AA2BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAsB;AAWtC,SAAA,YAAY,CAAC,aAA+B;;AACrC,WAAA,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACN,aAAA,UAAU,OAAO,QAAQ;AACtB;AAAA,MACV;AAAA,IACF;AAZE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EAAA;AAAA,EAkBjB,SAAS,SAA2C;;AAClD,SAAK,YAAY,KAAK;AAElB,SAAA,UAAK,YAAL,mBAAc,UAAU;AAC1B,WAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAmB;AAAA,IAAA,OACjE;AACD,UAAA,kBAAkB,OAAO,GAAG;AACzB,aAAA,QAAQ,QAAQ,KAAK,SAAS;AAAA,MAAA,OAC9B;AACL,aAAK,QAAQ;AAAA,MAAA;AAAA,IACf;AAIF,qBAAK,YAAL,mBAAc,aAAd;AAGA,YAAQ,IAAa;AAAA,EAAA;AAEzB;"}
@@ -2,6 +2,10 @@
2
2
  * @private
3
3
  */
4
4
  export type AnyUpdater = (prev: any) => any;
5
+ /**
6
+ * Type-safe updater that can be either a function or direct value
7
+ */
8
+ export type Updater<T> = ((prev: T) => T) | T;
5
9
  /**
6
10
  * @private
7
11
  */
@@ -13,3 +17,7 @@ export interface ListenerValue<T> {
13
17
  * @private
14
18
  */
15
19
  export type Listener<T> = (value: ListenerValue<T>) => void;
20
+ /**
21
+ * Type guard to check if updater is a function
22
+ */
23
+ export declare function isUpdaterFunction<T>(updater: Updater<T>): updater is (prev: T) => T;
@@ -0,0 +1,7 @@
1
+ function isUpdaterFunction(updater) {
2
+ return typeof updater === "function";
3
+ }
4
+ export {
5
+ isUpdaterFunction
6
+ };
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["/**\n * @private\n */\nexport type AnyUpdater = (prev: any) => any\n\n/**\n * Type-safe updater that can be either a function or direct value\n */\nexport type Updater<T> = ((prev: T) => T) | T\n\n/**\n * @private\n */\nexport interface ListenerValue<T> {\n prevVal: T\n currentVal: T\n}\n\n/**\n * @private\n */\nexport type Listener<T> = (value: ListenerValue<T>) => void\n\n/**\n * Type guard to check if updater is a function\n */\nexport function isUpdaterFunction<T>(\n updater: Updater<T>,\n): updater is (prev: T) => T {\n return typeof updater === 'function'\n}\n"],"names":[],"mappings":"AA0BO,SAAS,kBACd,SAC2B;AAC3B,SAAO,OAAO,YAAY;AAC5B;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/store",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Framework agnostic type-safe store w/ reactive framework adapters",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -41,10 +41,10 @@
41
41
  "src"
42
42
  ],
43
43
  "devDependencies": {
44
- "@angular/core": "^19.0.5",
45
- "@preact/signals": "^1.3.0",
46
- "solid-js": "^1.9.3",
47
- "vue": "^3.5.13"
44
+ "@angular/core": "^19.2.13",
45
+ "@preact/signals": "^1.3.2",
46
+ "solid-js": "^1.9.7",
47
+ "vue": "^3.5.14"
48
48
  },
49
49
  "scripts": {}
50
50
  }
package/src/store.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __flush } from './scheduler'
2
- import type { AnyUpdater, Listener } from './types'
2
+ import { isUpdaterFunction } from './types'
3
+ import type { AnyUpdater, Listener, Updater } from './types'
3
4
 
4
5
  export interface StoreOptions<
5
6
  TState,
@@ -48,11 +49,24 @@ export class Store<
48
49
  }
49
50
  }
50
51
 
51
- setState = (updater: TUpdater) => {
52
+ /**
53
+ * Update the store state safely with improved type checking
54
+ */
55
+ setState(updater: (prevState: TState) => TState): void
56
+ setState(updater: TState): void
57
+ setState(updater: TUpdater): void
58
+ setState(updater: Updater<TState> | TUpdater): void {
52
59
  this.prevState = this.state
53
- this.state = this.options?.updateFn
54
- ? this.options.updateFn(this.prevState)(updater)
55
- : (updater as any)(this.prevState)
60
+
61
+ if (this.options?.updateFn) {
62
+ this.state = this.options.updateFn(this.prevState)(updater as TUpdater)
63
+ } else {
64
+ if (isUpdaterFunction(updater)) {
65
+ this.state = updater(this.prevState)
66
+ } else {
67
+ this.state = updater as TState
68
+ }
69
+ }
56
70
 
57
71
  // Always run onUpdate, regardless of batching
58
72
  this.options?.onUpdate?.()
package/src/types.ts CHANGED
@@ -3,6 +3,11 @@
3
3
  */
4
4
  export type AnyUpdater = (prev: any) => any
5
5
 
6
+ /**
7
+ * Type-safe updater that can be either a function or direct value
8
+ */
9
+ export type Updater<T> = ((prev: T) => T) | T
10
+
6
11
  /**
7
12
  * @private
8
13
  */
@@ -15,3 +20,12 @@ export interface ListenerValue<T> {
15
20
  * @private
16
21
  */
17
22
  export type Listener<T> = (value: ListenerValue<T>) => void
23
+
24
+ /**
25
+ * Type guard to check if updater is a function
26
+ */
27
+ export function isUpdaterFunction<T>(
28
+ updater: Updater<T>,
29
+ ): updater is (prev: T) => T {
30
+ return typeof updater === 'function'
31
+ }