store.ts 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { create } from "zustand";
  2. import { combine, persist } from "zustand/middleware";
  3. import { Updater } from "../typing";
  4. import { deepClone } from "./clone";
  5. type SecondParam<T> = T extends (
  6. _f: infer _F,
  7. _s: infer S,
  8. ...args: infer _U
  9. ) => any
  10. ? S
  11. : never;
  12. type MakeUpdater<T> = {
  13. lastUpdateTime: number;
  14. markUpdate: () => void;
  15. update: Updater<T>;
  16. };
  17. type SetStoreState<T> = (
  18. partial: T | Partial<T> | ((state: T) => T | Partial<T>),
  19. replace?: boolean | undefined,
  20. ) => void;
  21. export function createPersistStore<T extends object, M>(
  22. state: T,
  23. methods: (
  24. set: SetStoreState<T & MakeUpdater<T>>,
  25. get: () => T & MakeUpdater<T>,
  26. ) => M,
  27. persistOptions: SecondParam<typeof persist<T & M & MakeUpdater<T>>>,
  28. ) {
  29. return create(
  30. persist(
  31. combine(
  32. {
  33. ...state,
  34. lastUpdateTime: 0,
  35. },
  36. (set, get) => {
  37. return {
  38. ...methods(set, get as any),
  39. markUpdate() {
  40. set({ lastUpdateTime: Date.now() } as Partial<
  41. T & M & MakeUpdater<T>
  42. >);
  43. },
  44. update(updater) {
  45. const state = deepClone(get());
  46. updater(state);
  47. set({
  48. ...state,
  49. lastUpdateTime: Date.now(),
  50. });
  51. },
  52. } as M & MakeUpdater<T>;
  53. },
  54. ),
  55. persistOptions as any,
  56. ),
  57. );
  58. }