Infer state and action types without an interface
TypeScript stores
Zustand · Function
Zustand's combine middleware merges an initial state with a creator for additional state and actions. It automatically infers the resulting store types, avoiding an explicit state definition in common TypeScript usage.
combine takes an initial state value and a creator for additional state and actions, then returns a state creator whose resulting type merges both parts. The middleware is useful when you want TypeScript to infer the store shape without declaring an explicit state interface.
combine<T extends object, U extends object>(initialState: T, additionalStateCreatorFn: StateCreator<T, [], [], U>): StateCreator<Omit<T, keyof U> & U, [], []>| Name | Type | Description |
|---|---|---|
initialState | T extends object | Initial state value; it may be any type except a function. |
additionalStateCreatorFn | StateCreator<T, [], [], U> | Creator receiving set, get, and store, usually returning additional state and actions. |
A state creator function with the combined shape Omit<T, keyof U> & U.
import { create } from 'zustand'
import { combine } from 'zustand/middleware'
const usePositionStore = create(
combine({ position: { x: 0, y: 0 } }, (set) => ({
setPosition: (position: { x: number; y: number }) => set({ position }),
})),
)
usePositionStore.getState().setPosition({ x: 10, y: 20 })
console.log(usePositionStore.getState().position)Creates a React store whose initial position and update action are inferred from the two arguments.
TypeScript stores
React applications
Vanilla Zustand
combine accepts an initial state and an additional state creator, then returns a state creator whose type combines the initial and added properties. This lets TypeScript infer state and action types without an explicit interface.
Follow-up: Why can the curried create form be omitted here? Because combine itself creates the state shape, so the resulting type is inferable.
The first argument supplies the initial state. The second receives set, get, and store, and normally returns the actions or other state properties to expose.
Follow-up: What restriction applies to the initial state? It may be any value except a function.
Import combine from zustand/middleware and pass it to create or createStore. The returned state creator can then be used to build either a React hook store or a vanilla store.
Follow-up: How does the middleware affect mutator typing? The reference lists combine as having no mutator because it does not mutate the store.
createcreateStorezustand/middlewaresetgetstore