7

I am not able to type the "state" parameter of a mapStateToProps

If I just change state : any instead of state: AppState it works and no error. But I would like to have a correct typing for my state parameter.

For now, I have this error on the mapStateToProps param of the connect()

No overload matches this call. The last overload gave the following error. Argument of type '(state: { quiz: IQuizInitialState; }) => StateProps' is no assignable to parameter of type 'MapStateToPropsParam'. Cannot assign the type '(state: { quiz: IQuizInitialState; }) => StateProps' to type 'MapStateToPropsFactory'. Parameters 'state' and 'initialState' are not compatible. Property 'quiz' is missing in type '{}' but required in type '{ quiz: IQuizInitialState; }'.ts(2769)

interface OwnProps {

}
interface StateProps {

}
interface DispatchProps {

}

type Props = OwnProps & StateProps & DispatchProps;


export class App extends Component<Props> {

  render() {
    return (
     <div>Hey</div>
    );
  }
}

const mapStateToProps = (state: AppState): StateProps => ({ 
})

const mapDispatchToProps = (dispatch: ThunkDispatch<{}, {}, AnyAction>): DispatchProps => {
    return {
    }
}


// The args 'mapStateToProps' generate the error
export default connect<StateProps,DispatchProps,OwnProps>(mapStateToProps, mapDispatchToProps)(App)

This is my rootReducer :

import { combineReducers } from 'redux';
import { QuizReducer } from './quiz';

const rootReducer = combineReducers({
    quiz: QuizReducer
});

export type AppState = ReturnType<typeof rootReducer>


export default rootReducer;

And the single reducer is :

import { TYPES } from '../actions/action-types';
import { IQuizListItem, Action } from '../models/index';
import { AnyAction } from 'redux';


export interface IQuizInitialState {
    quizListItem: IQuizListItem[]
}
const quizInitialState: IQuizInitialState = {
    quizListItem: []
}
export const QuizReducer = (state = quizInitialState, action: AnyAction): IQuizInitialState => {
    switch (action.type) {
        case TYPES.getQuizListItems:
            return {
                ...state,
                quizListItem: (action as Action<IQuizListItem[]>).payload
            }

        default:
            return state
    }
}

Thank you by advance guys !

Topsy
  • 1,023
  • 1
  • 11
  • 26

1 Answers1

15

The type of your state is the same type you use for the whole state. since mapStateToProps takes the whole state to pass it down to selectors. in your case I believe this would be the correct type IQuizInitialState.

const mapStateToProps = (state: IQuizInitialState): StateProps => ({ 

})

EDIT

In your comment you mention IQuizInitialState isnt your whole application state. Then that one is not the one you need. You need a type for the whole application state. To achieve that you could create an interface for every single reducer type meaning your IQuizInitialState but for the other reducers into a single interface.

Ill have to asume here since I dont have your code base but consider

combineReducers({potato: quizReducer, tomato: otherReduzer})

you'll need a type

interface IApplicationState {
potato: IQuizInitialState;
tomato: IOTherInterfaceYouDefinedForThisReducer;
}

your combineReducers will probable look like :

combineReducers<IApplicationState>({
  potato: quizReducer,
  tomato: otherReduzer
});

I hope you get the idea.

EDIT 2 After reading your last comment I noticed you are asking for the mapStateToProps with two arguments. and you are just defining one. Your connect generics seems wrong then. you should consider the following:

connect<StateProps, DispatchProps, Props, IApplicationState>

where:

  • StateProps : describes what was returned by mapStateToProps()
  • DispatchProps: describes what is returned by dispatchToProps()
  • Props: Your component props
  • IApplicationState: Represents your Apps Redux whole state
jstuartmilne
  • 4,398
  • 1
  • 20
  • 30
  • Thank your for your answer. But it does not work, plus it can't be right because IQuizInitialState is just the type of ONE of my reducers, not the whole app state. The state parameter in mapStateToProps is supposed to represent the whole state. And my Whole state type is AppState Thank you again. – Topsy Oct 23 '19 at 00:11
  • Here is the new error : No overload matches this call. The last overload gave the following error. L'argument de type '(state: IQuizInitialState) => StateProps' n'est pas attribuable au paramètre de type 'MapStateToPropsParam'. Impossible d'assigner le type '(state: IQuizInitialState) => StateProps' au type 'MapStateToPropsFactory'. Les types des paramètres 'state' et 'initialState' sont incompatibles. Property 'quizListItem' is missing in type '{}' but required in type 'IQuizInitialState'.ts(2769) – Topsy Oct 23 '19 at 00:15
  • So what you need is the type that **does** describe your whole app state. if IQuizInitialState is not it then you need to define an interface which describes the state of the whole store. since thats what the state param in mapStateToProps is – jstuartmilne Oct 23 '19 at 09:06
  • Thanks but unfortunately is does not work : Argument of type '(state: IAppState) => StateProps' can't be assigned to type 'MapStateToPropsParam' Can't assign (state: IAppState) => StateProps' to type 'MapStateToPropsFactory'. Type of parameter 'state' and 'initialState' are not compatible. Property 'quiz' is missing in type '{}' but required in type 'IStore'. I am really surprised that there is no way described on the net that is working to type this parameter ! – Topsy Oct 24 '19 at 23:29
  • Oh my god it works so the fourth parameter in the connect is the type for the state param ? – Topsy Oct 27 '19 at 03:09
  • yeah, apparently i missed an enter there ill edit. but yes. Glad it worked – jstuartmilne Oct 28 '19 at 13:14