Search code examples
javascripttypescriptreduxreact-reduxdispatch

Typescript: How to type the Dispatch in Redux


For example I want to remove the dispatch: any here:

export const fetchAllAssets = () => (dispatch: any) => {
  dispatch(actionGetAllAssets);
  return fetchAll([getPrices(), getAvailableSupply()]).then((responses) =>
    dispatch(actionSetAllAssets(formatAssets(responses))));
}

There are 2 actions I dispatch above, actionsGetAllAssets and actionsSetAllassets.

Here are the interfaces and actionCreators for both:

// Interfaces
interface IActions {
  GET_ALL_ASSETS: string;
  SET_ALL_ASSETS: string;
  GET_MARKET_PRICES: string;
  SET_MARKET_PRICES: string;
  ADD_COIN_PORTFOLIO: string;
  ADD_COINS_PORTFOLIO: string;
  UPDATE_COIN_PORTFOLIO: string;
  REMOVE_COIN_PORTFOLIO: string;
} 

interface IGetAllAssets {
  type: IActions['GET_ALL_ASSETS'];
  loading: boolean;
}

interface ISetAllAssets {
  type: IActions['SET_ALL_ASSETS'];
  assets: IAsset[];
  loading: boolean;
}

// ACTION CREATORS
const actionGetAllAssets = () => ({
  type: Actions.GET_ALL_ASSETS,
  loading: true
});

const actionSetAllAssets = (data: any) => ({
  type: Actions.SET_ALL_ASSETS,
  assets: data,
  loading: false
});

So then I tried the following:

export const fetchAllAssets = () => (dispatch: IGetAllAssets | ISetAllAssets) => {
  console.log('fetchAllAssets', dispatch);
  dispatch(actionGetAllAssets);
  return fetchAll([getPrices(), getAvailableSupply()]).then((responses) =>
    dispatch(actionSetAllAssets(formatAssets(responses))));
}

However it produces this Typescript error:

Cannot invoke an expression whose type lacks a call signature. Type 'IGetAllAssets | ISetAllAssets' has no compatible call signatures.ts(2349)

Thoughts? Or is there a different way to type a dispatch event?


Solution

  • I got a bit further!

    Dispatch is an event function, so got this to work:

    interface IAllAssets {
      type: IActions['GET_ALL_ASSETS'];
      assets?: IAsset[];
      loading: boolean;
    }
    
    // ACTIONS
    // Fetch assets from Nomics API V1.
    export const fetchAllAssets = () => (dispatch: (arg: IAllAssets) => (IAllAssets)) =>
    {
       dispatch(actionGetAllAssets());
       return fetchAll([getPrices(), getAvailableSupply()]).then((responses) =>
           dispatch(actionSetAllAssets(formatAssets(responses))));
    }
    

    However I'd still like to create a dispatch type, something like:

    interface IAllAssetsDispatch {
      dispatch: (arg: IAllAssets) => (IAllAssets)
    }
    
    export const fetchAllAssets = () => (dispatch: IAllAssetsDispatch) => {
    

    But this produces the same lacks a call signature error.

    GOT IT!

    Forgot about type that's what I needed to use instead of interface for functions:

    type DispatchAllAssets = (arg: IAllAssets) => (IAllAssets);
    
    type DispatchMarketPrices = (arg: ISetMarket) => (ISetMarket);
    
    type DispatchAddCoin = (arg: ICoinPortfolio) => (ICoinPortfolio);
    
    type DispatchAddCoins = (arg: ICoinsPortfolio) => (ICoinsPortfolio);
    
    // ACTIONS
    // Fetch assets from Nomics API V1.
    export const fetchAllAssets = () => (dispatch: DispatchAllAssets) => {
      dispatch(actionGetAllAssets());
      return fetchAll([getPrices(), getAvailableSupply()]).then((responses) =>
        dispatch(actionSetAllAssets(formatAssets(responses))));
    }
    
    // Fetch USD, USDC & USDT markets to filter out Exchange List.
    export const fetchMarketPrices = (asset: string) => (dispatch: DispatchMarketPrices) => {
      dispatch(actionGetMarketPrices);
      return getMarkets().then((res) => {
        if (res && res.marketUSD && res.marketUSDC && res.marketUSDT) {
          const exchangesForAsset = combineExchangeData(asset, res);
          return dispatch(actionSetMarketPrices(exchangesForAsset));
        }
        else {
          return dispatch(actionSetMarketPrices([]));
        }
      });
    }