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.
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 |
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.