When using Zustand the “classic way”, we often define an interface for the store:
interface BearState {
bears: number
increase: (by: number) => void
}
const useBearStore = create<BearState>()((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}))
But as the store grows and more actions are added, keeping this interface updated becomes annoying. Every time you add or rename an action, you must update the interface too — lots of extra typing and duplication.
So I switched to this cleaner pattern 👇
const initialState = { bears: 0 }
export type BearState = typeof initialState
export const useBearStore = create<BearState>()(() => initialState)
export const bearActions = {
increase(by: number) {
useBearStore.setState((state) => ({ bears: state.bears + by }))
},
}
✨ Why it’s better
-
No need to manually define and sync the interface
-
Actions are separated and can grow freely
-
typeof initialState automatically infers the correct types
-
Cleaner, easier to maintain, and still fully typed
.png)

