import type { StateCreator, StoreMutatorIdentifier } from '../vanilla' type SubscribeWithSelector = < T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [] >( initializer: StateCreator ) => StateCreator type Write = Omit & U type WithSelectorSubscribe = S extends { getState: () => infer T } ? Write> : never declare module '../vanilla' { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface StoreMutators { ['zustand/subscribeWithSelector']: WithSelectorSubscribe } } type StoreSubscribeWithSelector = { subscribe: { (listener: (selectedState: T, previousSelectedState: T) => void): () => void ( selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: { equalityFn?: (a: U, b: U) => boolean fireImmediately?: boolean } ): () => void } } type SubscribeWithSelectorImpl = ( storeInitializer: StateCreator ) => StateCreator const subscribeWithSelectorImpl: SubscribeWithSelectorImpl = (fn) => (set, get, api) => { type S = ReturnType type Listener = (state: S, previousState: S) => void const origSubscribe = api.subscribe as (listener: Listener) => () => void api.subscribe = ((selector: any, optListener: any, options: any) => { let listener: Listener = selector // if no selector if (optListener) { const equalityFn = options?.equalityFn || Object.is let currentSlice = selector(api.getState()) listener = (state) => { const nextSlice = selector(state) if (!equalityFn(currentSlice, nextSlice)) { const previousSlice = currentSlice optListener((currentSlice = nextSlice), previousSlice) } } if (options?.fireImmediately) { optListener(currentSlice, currentSlice) } } return origSubscribe(listener) }) as any const initialState = fn(set, get, api) return initialState } export const subscribeWithSelector = subscribeWithSelectorImpl as unknown as SubscribeWithSelector