3

I'm trying to copy the example of React+Redux component to typescript: https://medium.com/@stowball/a-dummys-guide-to-redux-and-thunk-in-react-d8904a7005d3

I'm hitting a deadend with the function:

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

I'm getting an error about how it's not mappable to ItemList.

One way around this I believe is to change the class declaration to:

class ItemList extends React.Component<{proper component map}, {proper state map}> {

However if I do this because the props have now been mapped I cannot simply include ItemList as and am now expected to provide the params.

Another option might be to: (props as any).fetchData() however this feels wrong.

Is there a way around this? Am I doing React+Redux wrong in typescript?

2
  • Why it's a problem to provide the params which are needed by the component? Commented Sep 13, 2017 at 10:49
  • Because then I can't just use <ItemList /> and have to provide params while in the javascript example I don't have to do that. Commented Sep 13, 2017 at 10:50

1 Answer 1

4

After you create everything, you export it together with connect.

interface PassedProps {
  productId: number;
}

interface StateToProps {
  addedProductIds: number[];
  quantityById: { [key: string]: number };
  quantity: number;
}

interface DispatchToProps {
  addToCart: (productId: number) => void;
  removeFromCart: (productId: number) => void;
}

// Needs to be added to src/store:GlobalStore interface with the correct prop name created from the name of the reducer
export interface CartState {
  addedProductIds: number[];
  quantityById: { [key: string]: number };
}

const mapStateToProps = (globalState: GlobalState): StateToProps => {
  const state: CartState = globalState.cart;

  return {
    addedProductIds: state.addedProductIds,
    quantityById: state.quantityById,
    quantity: Object.keys(state.quantityById).reduce( (sum: number, key: string) => state.quantityById[key] + sum, 0)
  };
};


const mapDispatchToProps = (dispatch: Dispatch<any>): DispatchToProps => {
  return {
    addToCart: (productId: number) => dispatch({ type: 'ADD_TO_CART', productId } as AddToCartAction),
    removeFromCart: (productId: number) => dispatch({ type: 'REMOVE_FROM_CART', productId } as RemoveFromCartAction),
  };
}

export type Props = PassedProps & StateToProps & DispatchToProps;

class CartButton extends Component<Props, CartState> {
  render() {
    const { quantity } = this.props;

    return (
      <View>
        <Text>
          { this.props.addedProductIds.length } type item is in the cart, totals to { quantity } item.
        </Text>
        <View>
          <Button
            onPress={this.onPressAdd.bind(this)}
            title="Add to Cart"
            color="#841584"
          />

          <Button
            onPress={this.onPressRemove.bind(this)}
            title="Removefrom Cart"
            color="#841584"
          />
        </View>
      </View>
    );
  }

  onPressAdd() {
    this.props.addToCart(this.props.productId);
  }

  onPressRemove() {
    this.props.removeFromCart(this.props.productId);
  }
}

export default connect<StateToProps, DispatchToProps, PassedProps>(mapStateToProps, mapDispatchToProps)(CartButton);

Then you can use it with specifying with the required props to be passed (PassedProps interface):

import CartButton from '../components/CartButton';

// ....
  render() {
    return(<CartButton productId={5} />)
  } 
Sign up to request clarification or add additional context in comments.

2 Comments

I tried to adapt this example but still no luck, the component is still expecting more parameters than just productId
my god, I just realized following the visual studio example the exports add 'as typeof' at the end like so: export default connect<StateToProps, DispatchToProps, PassedProps>(mapStateToProps, mapDispatchToProps)(CartButton) as typeof CartButton Removing that as per your example fixes everything. I can't beleive how much I've suffered over this, I'm not sure what that 'as typeof' bit is for or what it achieves but leaving it out fixes the issue, so your example was valid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.