Search code examples
reactjstypescriptzustand

Defining react component interface using typeof operator and passing props to it


I'm having problem defining interface for functional React component and passing props to it. Error is reproduced here.

It interface defined as

//Two zustand stores and their selectors
import { selector as listSelector, useListStore } from '../stores/list-form-store';
import { selector as elementSelector,useElementStore } from '../stores/element-form-store';
import { shallow } from 'zustand/shallow';

export interface ITagPanel {
  store: typeof useListStore | typeof useElementStore;
  selector: typeof listSelector | typeof elementSelector; 
}

export function TagPanel(props: ITagPanel) {
  const {tags, setTags} = props.store(props.selector, shallow);   

TagPanel need to accept several several different zustand stores and their selectors, so that TagPanel can be reused. props.store(props.selector, shallow); generates the error:

Expected 0 arguments, but got 2.  

Two stores above are defined as:

export const useElementStore = create<IElementStore>()((set) => ({...
export const useListStore = create<IListStore>()((set) => ({   

If I'm useListStore directly, doesn't generate the same error:

const {tags, setTags} = useListStore(listSelector, shallow);

Solution

  • You should really be using generic parameters instead of using a union:

    export interface ITagPanel<
      StoreType extends TagsStoreType,
      U extends TagsStoreType
    > {
      store: UseBoundStore<StoreApi<StoreType>>;
      selector: (state: StoreType) => U;
    }
    
    export function TagPanel<T extends TagsStoreType, U extends TagsStoreType>(
      props: ITagPanel<T, U>
    ) {
      const { tags, setTags } = props.store(props.selector, shallow);
    }
    

    where the generic parameters are constrained by this type:

    type TagsStoreType = {
      tags: { key: string; value: string }[];
      setTags: (tags: { key: string; value: string }[]) => void;
    };
    

    Playground