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

Code before:
        then(_onFulfilled) {
          return this as Thenable<any>
        },
        catch(onRejected) {
          return toThenable(onRejected)(e)
        },
      }
    }
  }

export const persist =
  <S extends State>(config: StateCreator<S>, _options: PersistOptions<S>) =>
  (set: SetState<S>, get: GetState<S>, api: PersistApi<S>): S => {
    let options = {
      getStorage: () => localStorage,
      serialize: JSON.stringify as (state: StorageValue<S>) => string,
      deserialize: JSON.parse as (str: string) => StorageValue<Partial<S>>,
      partialize: (state: S) => state,
      version: 0,
      merge: (persistedState: any, currentState: S) => ({
        ...currentState,
        ...persistedState,
      }),
      ..._options,
    }

    if (options.blacklist || options.whitelist) {
      console.warn(
        `The ${
          options.blacklist ? 'blacklist' : 'whitelist'
        } option is deprecated and will be removed in the next version. Please use the 'partialize' option instead.`
      )
    }

    let hasHydrated = false
    const onHydrateCallbacks: Parameters<
      PersistApi<S>['persist']['onHydrate']
    >[0][] = []
    let storage: StateStorage | undefined

    try {
      storage = options.getStorage()
    } catch (e) {
      // prevent error if the storage is not defined (e.g. when server side rendering a page)
    }

    if (!storage) {
      return config(
        (...args) => {
          console.warn(
            `Persist middleware: unable to update ${options.name}, the given storage is currently unavailable.`

Review comment (suggestion):
```suggestion
    let options: PersistOptions<S> = {
```
just an extra type checking.

Code after:
        then(_onFulfilled) {
          return this as Thenable<any>
        },
        catch(onRejected) {
          return toThenable(onRejected)(e)
        },
      }
    }
  }

export const persist =
  <
    S extends State,
    CustomSetState extends SetState<S>,
    CustomGetState extends GetState<S>,
    CustomStoreApi extends StoreApiWithPersist<S>
  >(
    config: (
      set: CustomSetState,
      get: CustomGetState,
      api: CustomStoreApi
    ) => S,
    baseOptions: PersistOptions<S>
  ) =>
  (set: CustomSetState, get: CustomGetState, api: CustomStoreApi): S => {
    let options = {
      getStorage: () => localStorage,
      serialize: JSON.stringify as (state: StorageValue<S>) => string,
      deserialize: JSON.parse as (str: string) => StorageValue<Partial<S>>,
      partialize: (state: S) => state,
      version: 0,
      merge: (persistedState: any, currentState: S) => ({
        ...currentState,
        ...persistedState,
      }),
      ...baseOptions,
    }

    if (options.blacklist || options.whitelist) {
      console.warn(
        `The ${
          options.blacklist ? 'blacklist' : 'whitelist'
        } option is deprecated and will be removed in the next version. Please use the 'partialize' option instead.`
      )
    }

    let hasHydrated = false
    const onHydrateCallbacks: Parameters<
      StoreApiWithPersist<S>['persist']['onHydrate']
    >[0][] = []
    let storage: StateStorage | undefined