Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 618
Leon Gaban Avatar asked Feb 23 '19 18:02

Leon Gaban


People also ask

What is the type of Redux dispatch?

Redux doesn't have a Dispatcher or support many stores. Instead, there is just a single store with a single root reducing function. As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree.

Can we use Redux in TypeScript?

As of React-Redux v8, React-Redux is fully written in TypeScript, and the types are included in the published package. The types also export some helpers to make it easier to write typesafe interfaces between your Redux store and your React components.


2 Answers

The Redux typings have a generic Dispatch<A> type you can use, where A is the type of action.

export const fetchAllAssets = () => (dispatch: Dispatch<IGetAllAssets | ISetAllAssets>) => {
  // ...
}
like image 58
Denis Washington Avatar answered Oct 10 '22 04:10

Denis Washington


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([]));
    }
  });
}
like image 5
Leon Gaban Avatar answered Oct 10 '22 05:10

Leon Gaban