How to use TypeScript with Zustand:
-
Define state types
typescriptinterface UserState { user: { id: string; name: string; email: string; } | null; isLoading: boolean; error: string | null; setUser: (user: UserState['user']) => void; setLoading: (loading: boolean) => void; setError: (error: string | null) => void; logout: () => void; } -
Create typed store
typescriptimport { create } from 'zustand'; const useUserStore = create<UserState>((set) => ({ user: null, isLoading: false, error: null, setUser: (user) => set({ user }), setLoading: (loading) => set({ loading }), setError: (error) => set({ error }), logout: () => set({ user: null, error: null }), })); -
Use in components
typescriptimport { useUserStore } from './store'; function UserProfile() { const user = useUserStore((state) => state.user); const isLoading = useUserStore((state) => state.isLoading); const error = useUserStore((state) => state.error); const logout = useUserStore((state) => state.logout); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {error}</div>; if (!user) return <div>Please login</div>; return ( <div> <h1>Welcome, {user.name}!</h1> <p>Email: {user.email}</p> <button onClick={logout}>Logout</button> </div> ); } -
Type inference and auto-completion
- TypeScript automatically infers types for state and actions
- Editors provide intelligent suggestions and type checking
-
Complex state types
- For nested states, use nested interfaces
- For dynamic states, use generics
-
Middleware type support
- Type configuration for persist middleware
- Type definitions for custom middleware
Best Practices:
- Create separate type definition files for each store
- Use interfaces to clearly define state structure and action signatures
- Use TypeScript's type checking to catch potential errors
- Combine with generics to handle complex state types