13
votes

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

2 Answers

11
votes

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)
0
votes

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