Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No overload matches this call error for createStructuredSelector with typescript. #428

Closed
vijhhh2 opened this issue Oct 19, 2019 · 7 comments
Milestone

Comments

@vijhhh2
Copy link

vijhhh2 commented Oct 19, 2019

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.

@amglt
Copy link

amglt commented Nov 27, 2019

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.

@drillprop
Copy link

drillprop commented Nov 28, 2019

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

@amglt
Copy link

amglt commented Nov 28, 2019

@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,
  });
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

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 🙂

@oatkiller
Copy link

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.

@arendjr
Copy link

arendjr commented Dec 7, 2020

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.

@markerikson
Copy link
Contributor

I just published https://github.com/reduxjs/reselect/releases/tag/v4.1.0-alpha.0 , which should fix this issue. Can folks try it out and give us feedback?

@markerikson markerikson added this to the 4.1 milestone Oct 17, 2021
@markerikson
Copy link
Contributor

Should be fixed by #486 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants
@oatkiller @arendjr @markerikson @amglt @vijhhh2 @drillprop and others