Use a state type to check a store's fields and actions, then derive the complete store type for components and utilities.
When to use this
Use this pattern when you want TypeScript to check the store's initial state and action signatures, and want one reusable type that stays aligned with the store. Install zustand if it is not already in your project:
bashnpm install zustand
1. Declare the state shape and create the store
Pass your state-and-actions type to create in its curried form, create<State>()(creator). The type argument checks the object returned by the creator, while TypeScript infers the set callback from that type. The extra call lets you provide the state type while leaving the creator's other types inferred.
Use ExtractState to derive and export the complete state-and-actions type from the bound store.
tsimport { create, type ExtractState } from 'zustand'
interface BearState {
bears: number
food: string
feed: (food: string) => void
}
export const useBearStore = create<BearState>()((set) => ({
bears: 2,
food: 'honey',
feed: (food) => set({ food }),
}))
export type BearStoreState = ExtractState<typeof useBearStore>
The store starts with two bears and honey. TypeScript checks that the returned object supplies both state fields and the feed action, and checks the action's argument as a string.
2. Reuse the store type
The exported alias gives utilities the full state-and-actions type without a second version of the store's shape.
tsimport type { BearStoreState } from './store'
export function describeBears(state: BearStoreState): string {
return `${state.bears} bears eat ${state.food}`
}
In a React component, read the store and pass it to the typed utility. The button calls the colocated action; the displayed summary changes from honey to berries.
tsximport { useBearStore } from './store'
import { describeBears } from './summary'
export function App() {
const state = useBearStore()
return (
<main>
<p>{describeBears(state)}</p>
<button onClick={() => state.feed('berries')}>Feed berries</button>
</main>
)
}
For the React entry-point code that mounts App, use React quick start; this page adds the typed store contract and reusable state-and-actions type.
What to watch for
- Keep state updates immutable. If you update a nested object, copy its existing fields; see Update nested state.
- When a component needs only part of the state, select that part rather than subscribing to the whole store; see Select state efficiently.
- Do not call
getsynchronously while the initial state creator is running: the state has not been created yet. Use it from an action after store creation instead.
See it running
Open the Zustand live demo to see a running Zustand application.
Was this page helpful?