Reduce selector boilerplate
A store has many state properties and actions, making individual selector declarations repetitive.
Zustand · Const
Zustand's auto-generating selectors pattern augments a store with a typed use object. It creates one selector per key in getState(), allowing direct access such as store.use.bears() and store.use.increment().
The guide presents a createSelectors helper that augments a Zustand store with a use object. It iterates over the keys returned by getState() and assigns a selector function for each key; the resulting store exposes typed property and action selectors such as .use.bears() and .use.increment().
const createSelectors = <S extends UseBoundStore<StoreApi<object>>>(_store: S) => {
const store = _store as WithSelectors<typeof _store>
store.use = {}
for (const k of Object.keys(store.getState())) {
;(store.use as any)[k] = () => store((s) => s[k as keyof typeof s])
}
return store
}use object.useStore(_store, selector).import { create } from 'zustand'
type BearState = {
bears: number
increment: () => void
}
const createSelectors = <S extends { getState: () => object; (selector: (state: any) => any): any }>(store: S) => {
const typedStore = store as S & { use: { [K in keyof ReturnType<S['getState']>]: () => ReturnType<S['getState']>[K] } }
typedStore.use = {} as typeof typedStore.use
for (const key of Object.keys(store.getState())) {
;(typedStore.use as any)[key] = () => store((state: any) => state[key])
}
return typedStore
}
const useBearStore = create<BearState>((set) => ({
bears: 0,
increment: () => set((state) => ({ bears: state.bears + 1 })),
}))
const useBearStoreWithSelectors = createSelectors(useBearStore)
const bears = useBearStoreWithSelectors.use.bears()
useBearStoreWithSelectors.use.increment()Creates a typed use object whose properties are generated from the store's current state keys. Each generated function selects one property, so components can call selectors such as use.bears() or use.increment().
A store has many state properties and actions, making individual selector declarations repetitive.
Components need concise, typed access to individual state members.
A project uses Zustand's vanilla store API rather than a React hook store.
The helper casts the store to a type that includes a use property, initializes that object, then loops over Object.keys(store.getState()). For every key it creates a selector function that returns the corresponding state member.
Follow-up: How does the vanilla version differ? It accepts a StoreApi and uses useStore(_store, selector) inside each generated selector rather than calling the React store directly.
For a React store, the generated API is accessed through the augmented store, for example useBearStore.use.bears() for state and useBearStore.use.increment() for an action. The same usage pattern applies to the vanilla-store helper after it has been created.
Follow-up: What determines which selectors are generated? The keys present in store.getState() at helper-creation time determine the generated use members.
createSelectors implementations?The guide provides separate implementations for React and vanilla stores. The React implementation invokes the store with a selector, while the vanilla implementation passes the store and selector to Zustand's useStore function.
Follow-up: Why should the helper match the store kind? The invocation mechanism differs between hook-based React stores and vanilla store APIs, so using the wrong helper does not follow the documented implementation.
createuseStoreselectorsvanilla storeStoreApi