Copy import type { StateCreator , StoreMutatorIdentifier } from '../vanilla.ts'
type SubscribeWithSelector = <
T ,
Mps extends [ StoreMutatorIdentifier , unknown ][] = [] ,
Mcs extends [ StoreMutatorIdentifier , unknown ][] = [] ,
>(
initializer : StateCreator <
T ,
[ ... Mps , [ 'zustand/subscribeWithSelector' , never ]] ,
Mcs
> ,
) => StateCreator < T , Mps , [[ 'zustand/subscribeWithSelector' , never ] , ... Mcs ]>
type Write < T , U > = Omit < T , keyof U > & U
type WithSelectorSubscribe < S > = S extends { getState : () => infer T }
? Write < S , StoreSubscribeWithSelector < T >>
: never
declare module '../vanilla' {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface StoreMutators < S , A > {
[ 'zustand/subscribeWithSelector' ] : WithSelectorSubscribe < S >
}
}
type StoreSubscribeWithSelector < T > = {
subscribe : {
( listener : (selectedState : T , previousSelectedState : T ) => void ) : () => void
< U >(
selector : (state : T ) => U ,
listener : (selectedState : U , previousSelectedState : U ) => void ,
options ?: {
equalityFn ?: (a : U , b : U ) => boolean
fireImmediately ?: boolean
} ,
) : () => void
}
}
type SubscribeWithSelectorImpl = < T extends object >(
storeInitializer : StateCreator < T , [] , []> ,
) => StateCreator < T , [] , []>
const subscribeWithSelectorImpl : SubscribeWithSelectorImpl =
(fn) => (set , get , api) => {
type S = ReturnType < typeof fn>
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