0

I am trying to write a React Redux component using Typescript following the documentation in Redux Getting Started and Proper Typing of react-redux Connected Components and am getting a type error on my connect function.

My app uses Redux to maintain a table of questions.

state.tsx

import {AnyAction, combineReducers} from "redux";

const ADD_QUESTION = "ADD_QUESTION";

export interface Question {
    id: number,
    text: string
}

export interface State {
    questions: QuestionsTable
}

interface QuestionsTable {
    nextId: number,
    questions: Question[]
}

const questions = (state: State = {questions: {nextId: 0, questions: []}}, action: AnyAction): State => {
    const questions = state.questions;
    switch (action.type) {
        case ADD_QUESTION:
        return {
            ...state,
            questions: {
                ...questions,
                nextId: questions.nextId + 1,
                questions: questions.questions.concat([{id: questions.nextId, text: action.text}])
            }
        };
        default:
            return questions
    }
};

export const reducers = combineReducers({
    questions
});

A Questions component displays them. I use connect to create QuestionsContainer from that.

questions.tsx

import React from "react"
import {Question, State} from "../state";
import {connect} from "react-redux";

export type QuestionsProps = {
    questions: Question[]
}

const Questions: React.FC<QuestionsProps> = ({questions}) => {
    return (
        <div>
            <ul>
                {questions.map(question => (
                    <li>{question.text}</li>
                ))}
            </ul>
        </div>
    )
};

const mapStateToProps = (state: QuestionsTable): QuestionsProps => {
    return {questions: state.questions.questions};
};

export const QuestionsContainer = connect<QuestionsProps>(mapStateToProps)(Questions);

My top-level app displays this container component.

App.tsx

import React from "react";
import "./App.css";
import {reducers} from "./state";
import {createStore} from "redux"
import {Provider} from "react-redux"
import {QuestionsContainer} from "./components/questions";

const store = createStore(reducers);
const App: React.FC = () => {
    return (
        <Provider store={store}>
            <div className="App">
                <QuestionsContainer/>
            </div>
        </Provider>
    );
};

export default App;

I get a type error in my call to connect.

Error:(61, 59) TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '(state: State) => QuestionsProps' is not assignable to parameter of type 'MapStateToPropsParam<QuestionsProps, {}, {}>'.
      Type '(state: State) => QuestionsProps' is not assignable to type 'MapStateToPropsFactory<QuestionsProps, {}, {}>'.
        Types of parameters 'state' and 'initialState' are incompatible.
          Property 'questions' is missing in type '{}' but required in type 'State'.

If I suppress this error with @ts-ignore and log the value of questions passed to my Questions component I see this.

{"nextId":0,"questions":[]}

I can't figure out why the nextId field is there even though mapStateToProps dereferences state.questions.questions.

What is the correct way to set this up?

3
  • 1
    In a reducer you are returning {nextId: 0, questions: []} as a default value of questions. According to your mapStateToProps, you have to use return {questions: state.questions.questions}; Also, first parameter of reducer is a state Commented Nov 23, 2019 at 16:14
  • I was confused about the arguments that should be passed to a reducer. I edited the question to fix this. I'm still seeing pretty much the same error, though. Commented Nov 23, 2019 at 16:51
  • export const QuestionsContainer = connect<QuestionsProps, {}>(mapStateToProps)(Questions); can you try exporting it this way and see if you get the same error? Commented Nov 24, 2019 at 0:42

1 Answer 1

1

Okay I will try it from phone Sorry for formatting

import {AnyAction, combineReducers} from "redux";

const ADD_QUESTION = "ADD_QUESTION";

export interface Question {
    id: number,
    text: string
}

interface State {
    nextId: number,
    items: Question[]
}

const initialState: State = {nextId: 0,  items: []}

const questions = (state = initialState, action: AnyAction): State => {
    switch (action.type) {
        case ADD_QUESTION:
        return {
            ...state,
            items: action.items,
            nextId: action.nextId
        };
        default:
            return state
    }
};

export const reducers = combineReducers({
    questions
});

That's how I see your reducer

Then in component in mapStateToProps questions: state.questions.items

Sign up to request clarification or add additional context in comments.

Comments

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.