Type state and actions
Define a store whose fields and actions must remain consistent as it evolves.
Zustand · Const
Zustand store typing uses a state-and-actions type with the curried create<T>()(...) form. This provides compile-time checking and typed selectors without requiring an interface when TypeScript can infer the shape.
Type the store by supplying its state-and-actions shape to the curried create call. The declared interface validates the initial state and action implementations, while TypeScript infers action parameter types and selector results from that shape.
create<T>()((set, get, store) => state)| Name | Type | Description |
|---|---|---|
T | State type | The state-and-actions shape used to type the store creator. |
A typed bound Zustand store, such as UseBoundStore<StoreApi<BearState>>.
ExtractState is available for deriving a reusable store type outside the original store declaration.create<T>()(...) form rather than the uncurried form when annotating a store, because this is the recommended pattern for inferring the store type.create; moving it elsewhere can prevent the contextual inference that gives actions their intended types.import { create } from 'zustand'
interface BearState {
bears: number
increase: (by: number) => void
}
const useBearStore = create<BearState>()((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}))
export function Bears() {
const bears = useBearStore((state) => state.bears)
const increase = useBearStore((state) => state.increase)
return <button onClick={() => increase(1)}>{bears}</button>
}The generic describes the store’s state and actions, while the curried form lets Zustand infer the store type.
Define a store whose fields and actions must remain consistent as it evolves.
Read only selected fields from a store with inferred selector results.
Share a store’s state-and-actions shape with tests, props, or utilities.
Use an interface or type for the state and actions, then pass it to the curried creator: create<BearState>()((set) => ({ ... })). This checks that the returned store matches the declared shape and gives selectors and actions typed results.
Follow-up: Why is the extra pair of parentheses used? The curried form allows the store type to be annotated while the remaining creator details are inferred.
The store type includes both data and callable actions, such as bears: number and increase: (by: number) => void. The generic makes missing properties and incompatible values compile-time errors.
Follow-up: How can the declaration avoid repeating property types? Define an initial state object and use typeof initialState when the inferred object shape is sufficient.
A selector such as (state) => state.bears reads only the selected part of the typed store. TypeScript infers the selector result and validates the selected property against the store shape.
Follow-up: How can the full store type be reused outside the store declaration? Use Zustand’s ExtractState helper to obtain the state-and-actions type for props, tests, or utilities.
createExtractStateselectorsStoreApiUseBoundStore