Reselect: No overload matches this call error for createStructuredSelector with typescript.

Created on 19 Oct 2019  路  7Comments  路  Source: reduxjs/reselect

Hi, I am trying to build an react redux typescript app.

I am using reslect library to create selectors.

I am getting an error while using createStructuredSlectore. Please find the error beolow.

Error: No overload matches this call

Please find the code below:

import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';

import { toggleDropDown } from '../../redux/cart/cart.actions';
import { selectItemCount } from '../../redux/cart/cart.selectors';

import { ReactComponent as ShoppingIcon } from '../../assets/11.2 shopping-bag.svg.svg';

import './cart-icon.component.scss';

interface ICartIconProps {
    toggleDropDown: () => void;
    itemCount: number;
}

const CartIcon: React.FC<ICartIconProps> = ({toggleDropDown, itemCount}) => (
    <div className='cart-icon' onClick={toggleDropDown}>
        <ShoppingIcon className='shopping-icon'/>
        <span className='item-count'>{itemCount}</span>
    </div>
)

const mapDispatchToProps = (dispatch: import('redux').Dispatch) => ({
    toggleDropDown: () => dispatch(toggleDropDown())
})

// If I use Below code its working fine
// const mapStateToProps = (state: AppState) => ({
//     itemCount: selectItemCount(state)
// })

// Iam getiing error here with below code
const mapStateToProps = createStructuredSelector({
    itemCount: selectItemCount,
})



export default connect(mapStateToProps, mapDispatchToProps)(CartIcon);

Slectors.ts

import { createSelector } from 'reselect'

import { AppState } from '../store'
import { ShopItem } from '../../models/collection.model'

const selectCart = (state: AppState) => state.cart

export const selectCartItems = createSelector(
  [selectCart],
  cart => cart.cartItems
);

export const selectHidden = createSelector(
  [selectCart],
  cart => cart.hidden
);

export const selectItemCount = createSelector(
  [selectCartItems],
  (cartItems: ShopItem[]) => {
    return cartItems.reduce(
      (accumulatedValue, cartItem) =>
        accumulatedValue + (cartItem.quantity as number),
      0
    )
  }
);

cart.reducer.ts

import { CartActionsTypes } from "./cart.types";
import { addItemToCart } from "./cart.utils";

const INITIAL_STATE = {
    hidden:  true,
    cartItems: []
};

const cartReducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case CartActionsTypes.TOGGLE_CART_DROPDOWN:
            return {
                ...state,
                hidden: !state.hidden
            }
        case CartActionsTypes.ADD_ITEM:
            return {
                ...state,
                cartItems: addItemToCart(state.cartItems, action.payload)
            }    
        default:
            return state;
    }
}

export default cartReducer;

also It is good to have an example.

Most helpful comment

If you don't want to have to manually specify the generic types, please have a look at the snippet provided in #476. This allows the types to be derived automatically and I hope it works for you.

All 7 comments

Hi,

Got exactly the same issue on the 'header' property from object passed to createStructuredSelector in index.tsx.

No overload matches this call. ts(2769)

index.tsx

import React from 'react';
import { Dispatch, AnyAction, bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { getHomeHeaderRequest } from 'stores/actions/home.actions';
import { createStructuredSelector } from 'reselect';
import { selectHeader } from 'stores/selectors/home.selectors';

const mapStateToProps = () =>
  createStructuredSelector({
    header: selectHeader,
  });

const mapDispatchToProps = (dispatch: Dispatch<AnyAction>) =>
  bindActionCreators(
    {
      getHomeHeader: getHomeHeaderRequest,
    },
    dispatch,
  );

type HomeProps = ReturnType<typeof mapStateToProps> &
  ReturnType<typeof mapDispatchToProps>;

class Home extends React.Component<HomeProps, {}> {
  componentDidMount() {
    const { getHomeHeader } = this.props;
    getHomeHeader();
  }

  render() {
    const { header } = this.props;
    console.log(this.props);

    return (
      <div>
        <p>Hello from {header.title} page</p>
      </div>
    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Home);

selectors.ts

import { createSelector } from 'reselect';
import { AppState } from 'stores/rootReducer';
import { homeReducerInitialState } from 'stores/reducers/home.reducer';

/* eslint-disable import/prefer-default-export */

const selectHomeStore = (state: AppState) =>
  state.Home || homeReducerInitialState;

export const selectHeader = createSelector(
  selectHomeStore,
  homeState => homeState.header,
);

However, the code is working fine. It's just boring to have that typescript error.

I just figured it out
You need to pass between angle brackets types of your state and every single selectors.
Like this:

const structuredSelector = createStructuredSelector<
  ReduxState, { isTimerStart: boolean; timeleft: number; isInterval: boolean }
>({
  isTimerStart: selectIsTimerStart,
  timeleft: selectTimeleft,
  isInterval: selectIsInterval
});

You can also do just like that:

const structuredSelector = createStructuredSelector<any, any>({
  isTimerStart: selectIsTimerStart,
  timeleft: selectTimeleft,
  isInterval: selectIsInterval
});

But i dont think it's a good solution

@drillprop Thank that's starting to be better

Can you tell me why

const mapStateToProps = () =>
  createStructuredSelector<
    AppState,
    { header: HomeHeader; isLoading: boolean }
  >({
    header: selectHeader,
    isLoading: selectLoading,
  });

is working ?

But why

const mapStateToProps = () =>
  createStructuredSelector<AppState, HomeSelectors>({
    header: selectHeader,
    isLoading: selectLoading,
  });

```javascript
export interface HomeSelectors {
header: HomeHeader;
isLoading: boolean;
}

tells me that header or isLoading prop does not exist ? Also tested with HomeSelectors as a type. I would like to pass an interface or a type.

EDIT: 
Well, finally it's not working in both ways 馃槥 

My props are defined that way 
```javascript
type HomeProps = ReturnType<typeof mapStateToProps> &
  ReturnType<typeof mapDispatchToProps>;

EDIT 2:
Finally solved it by doing it like that

const mapStateToProps = () =>
  createStructuredSelector<AppState, HomeSelectors>({
    header: selectHeader,
    isLoading: selectLoading,
  });

type HomeProps = HomeSelectors & ReturnType<typeof mapDispatchToProps>;

Thank you for the help 馃檪

I'm using this type instead of the builtin one:

type CeateStructuredSelector = <SelectorMap extends { [key: string]: (...args: any[]) => any }>(
  selectorMap: SelectorMap
) => (
  state: SelectorMap[keyof SelectorMap] extends (state: infer State) => unknown ? State : never
) => {
  [Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>;
};

http://www.typescriptlang.org/play/?ts=3.8-Beta&ssl=5&ssc=2&pln=3&pc=1#code/PTAEFMEMGMAtQG6QDYFdygPYDNQGVxlxoAXTAJwFlIAHUAZ1k1WQBNQAjDE2DeyALbgANKEgA7dj3ABPBkxbsuoaQ0EZI9Fb3wlIJbrH3aM5cCVTlx4dvULEy5FZADW4egCgQJ0GYtXEFHR5ZjZODXEsDgArB1AAd14zQLR3UCMEDV9zS0iSGRoMDk0bLDydOyJSClABWgA6HzcZLTqSOFAASxJQVBoAfg98wtAAYSgDPBJyVFJLGwIqx1AAXlAAHkWHCmo6cAAPA0ktAG9QAG1mgC4Gac7xAHMAXRuACnqPyHIH+huJGXOTwAlKsAHxicRyAC+oNeHlADHs1SotBuW2Ruw8IJW4LhCPoegMaKRjl2l1kOHwJJ2tCeEEO4GOoFeBP04Bu92w4CcUzZ2PBqHELnEmHikX6ujZoBu1ky5CxYNAJ3hFwA0rIupFmpT0aTaTcAEo5KwAFQK4E21JRNHO6pkT1BAG4PFDnR5WMRkF8MNBMOICaBoGY2VMZnMzKxdRQbuMQ9NZv4FlaPB5ff6egSw4nI4RkatA8HJvHw0mlhRXsqEQjIG9WUTQOJUAIuOR+aAAOTt4QqhEcWuE9kNpsttvWeKgAAibJdQJTmYT8xzyGRrwAjED6hwgA

Sorry, it doesn't support parametric stuff or some other options, but it should be possible to extend it if you need it. I might submit this as a PR later.

What you need to do is pass the correct props to createStructuredSelector(). Simply export the type from the selectors.

selectors.ts

export type ItemCount = ReturnType<typeof selectItemCount>;

Change the interface to a union type and give it to the CartIcon componenent.

CartIcon.tsx

import { ItemsCount } from 'selectors';

type CartIconProps = ItemCount & {
    toggleDropdown: () => object
};

Now there shouldn't be any overload from the created selector.

const mapStateToProps = createStructuredSelector<AppState, ItemCount>({
    itemCount: selectItemCount,
});

If you don't want to have to manually specify the generic types, please have a look at the snippet provided in #476. This allows the types to be derived automatically and I hope it works for you.

TypeError: Object(...) is not a function
Module.
E:/React/crwn-clothing/src/components/cart-dropdown/cart-dropdown.component.jsx:31
28 | cartItems: selectCartItem,
29 | });
30 |

31 | export default withRouter(connect(mapStateToProps)(CartDropdown));
32 |

Was this page helpful?
0 / 5 - 0 ratings