22

I'm new to Redux and new to Typescript.

I've found a fairly good basic cut-down version of what I'm trying to do in the react-redux docs.

The code is like this :

import * as actionCreators from '../actions/index'
import { bindActionCreators } from 'redux'
import React, { Component } from 'react'
import { connect } from 'react-redux'

class TodoApp extends Component {
    render() {
        return (<div>test!</div>)
    }
}
function mapStateToProps(state) {
  return { todos: state.todos }
}

function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(actionCreators, dispatch) }
}


export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)

Both my code editor (VS Code with the TSLint extension) and tsc highlight that final (TodoApp) as an error, and this is the message I get :

src/components/test.tsx(20,61): error TS2345: Argument of type 'typeof TodoApp' is not assignable to parameter of type 'ComponentType<{ todos: any; } & { actions: typeof "(filepath)...'. Type 'typeof TodoApp' is not assignable to type 'StatelessComponent<{ todos: any; } & { actions: typeof "(filepath)...'. Type 'typeof TodoApp' provides no match for the signature '(props: { todos: any; } & { actions: typeof "(filepath)/actions/index"; } & { children?: ReactNode; }, context?: any): ReactElement | null'.

20 export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)

My problem is that I don't entirely understand exactly what mapStateToProps and connect are doing, but prior to getting that understanding,
I'd like to know if there is a code change I can make here to fix this Typescript "error".

2 Answers 2

18

Your react component expects no props, so your connect has an error as it infers that mapStateToProps and mapDispatchToProps should both return empty objects

You can get around this by adding type defs for the react props, but there is also a lot of unsafe use of implicit any. If you were to fully type this application for safety's sake it would look something like this ....

interface ITodo {
  description: string
}

interface ITodosState {
  todos: ITodo[]
}

interface ITodoProps {
  todos: ITodo[]
}

interface ITodoActionProps {
  someAction: () => void
}

class TodoApp extends React.Component<ITodoProps & ITodoActionProps> {
    render() {
        return (<div>test!</div>)
    }
}

function mapStateToProps(state: ITodosState): ITodoProps {
  return { todos: state.todos }
}

function mapDispatchToProps(dispatch: Dispatch<ITodosState>): ITodoActionProps {
  return bindActionCreators({ someAction: actionCreators.someAction }, dispatch)
}

export default connect<ITodoProps, ITodoActionProps, {}>(mapStateToProps, mapDispatchToProps)(TodoApp)
Sign up to request clarification or add additional context in comments.

1 Comment

My actual working example was not quite the same as what I posted above, and my solution was actually changing interface ITodoActionProps { someAction: () => void } to interface ITodoActionProps { someAction: typeof actionCreators.someAction } Your great answer made that clear right away - thank you !
2

You haven't typed TodoApp's props.

type Props = {
    todos: any[] // What ever the type of state.todos is
    actions: {
       addTodo: Dispatch<any>
    }
}

class TodoApp extends React.Component<Props> {
    render() {
        return <div>test!</div>
  }
}

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.