Repository: pmndrs/zustand
File: src/middleware.ts (TypeScript)

Code before:
  // the set(state) value would be later overridden with initial state by create()
  // to avoid this, we merge the state from localStorage into the initial state.
  // TODO: find a better solution for this
  let stateFromStorageInSync: S | undefined
  const postRehydrationCallback = onRehydrateStorage?.(get()) || undefined
  // bind is used to avoid `TypeError: Illegal invocation` error
  toThenable(storage.getItem.bind(storage))(name)
    .then((storageValue) => {
      if (storageValue) {
        return deserialize(storageValue)
      }
    })
    .then((deserializedStorageValue) => {
      if (deserializedStorageValue) {
        if (deserializedStorageValue.version !== version) {
          if (migrate) {
            return migrate(
              deserializedStorageValue.state,
              deserializedStorageValue.version
            )
          }
          console.error(
            `State loaded from storage couldn't be migrated since no migrate function was provided`
          )
        } else {
          stateFromStorageInSync = deserializedStorageValue.state
          set(deserializedStorageValue.state)
        }
      }
    })
    .then((migratedState) => {
      if (migratedState) {
        stateFromStorageInSync = migratedState as S
        set(migratedState as PartialState<S, keyof S>)
        return setItem()
      }
    })
    .then(() => {
      postRehydrationCallback?.(get(), undefined)
    })
    .catch((e: Error) => {
      postRehydrationCallback?.(undefined, e)
    })

  const configResult = config(
    (...args) => {
      set(...args)
      void setItem()
    },
    get,
    api

Review comment (suggestion):
```suggestion
        if ((deserializedStorageValue.version ?? false) && deserializedStorageValue.version !== version) {
```
see #409

Code after:
  }

  const savedSetState = api.setState

  api.setState = (state, replace) => {
    savedSetState(state, replace)
    void setItem()
  }

  // rehydrate initial state with existing stored state

  // a workaround to solve the issue of not storing rehydrated state in sync storage
  // the set(state) value would be later overridden with initial state by create()
  // to avoid this, we merge the state from localStorage into the initial state.
  let stateFromStorageInSync: S | undefined
  const postRehydrationCallback = onRehydrateStorage?.(get()) || undefined
  // bind is used to avoid `TypeError: Illegal invocation` error
  toThenable(storage.getItem.bind(storage))(name)
    .then((storageValue) => {
      if (storageValue) {
        return deserialize(storageValue)
      }
    })
    .then((deserializedStorageValue) => {
      if (deserializedStorageValue) {
        if (deserializedStorageValue.version !== version) {
          if (migrate) {
            return migrate(
              deserializedStorageValue.state,
              deserializedStorageValue.version
            )
          }
          console.error(
            `State loaded from storage couldn't be migrated since no migrate function was provided`
          )
        } else {
          stateFromStorageInSync = deserializedStorageValue.state
          set(deserializedStorageValue.state)
        }
      }
    })
    .then((migratedState) => {
      if (migratedState) {
        stateFromStorageInSync = migratedState as S
        set(migratedState as PartialState<S, keyof S>)
        return setItem()
      }
    })
    .then(() => {
      postRehydrationCallback?.(get(), undefined)
    })