Search code examples
reactjstypescriptreact-hooksreact-contextreact-state-management

How to define Typescript properties and types for a React Action Hook Store


I am creating a react state management store using hooks, after the 'Action Hooks pattern' described here by Tanner Linsley.

I am learning Typescript and am trying to create this project using it but keep running into an error when calling the custom hook to consume the store:

'Property 'useStore' does not exist on type '() => { Provider: ({ initialValue, children }: { initialValue?: {}; children: any; }) => Element; useStore: () => any;}' ts(2339)

I tested it in plain react and it is working, so it is a type or property definition issue with Typescript.

Generic Store created (No typescript errors):

interface IState {}

const initialState: IState = {}

export default function newStore() {
  const context = React.createContext<IState>(initialState)

  const Provider = ({ initialValue = {}, children }): JSX.Element => {
    const [state, setState] = useState(initialValue)
    const contextValue = useMemo(() => [state, setState], [state])

    return <context.Provider value={contextValue}>{children}</context.Provider>
  }
  const useStore = () => useContext(context)

  return { Provider, useStore }
}

Store Action Hooks (the error is shown for both instances of useStore):

import store from "./makeStore";

export const useGalleryOpen = () => {
  const [{ galleryOpen }] = store.useStore()
  return galleryOpen
}

export const useGalleryToggle = () => {
  const [_, setState] = store.useStore()
  return () =>
    setState(prev => ({
      ...prev,
      galleryOpen: !prev.galleryOpen,
    }))
}

Any advice greatly appreciated.


Solution

  • The key point of the problem (it's visible in your code sandbox and I've edited your question to include it) is the store definition.

    You define store as import store from "./makeStore";

    So store is a function that, when called, returns an object containing

    {
      Provider: any;
      useStore(): any;
    }
    

    when you consume it with store.useStore() you're making the mistake. store is a function which return value is an object containing the useStore function.

    Everything goes well replacing

    store.useStore()
    

    with

    store().useStore()
    

    Let me know if you need more help 😊