3
votes

I have the following example:

import * as React from "react";
import { connect } from 'react-redux';


interface IMessage {
    message : string;
}

class SayMessage extends React.Component<IMessage, {}>{
    render () {
        return (<div>{this.props.message}</div>);
    }
}


function mapStateToProps( state : any ) : IMessage {
  return { message : "Hello, world" };
}
const SayMessageContainer = connect(mapStateToProps)(SayMessage);

export class SomeOtherView extends React.Component<{},{}>{
    render (){
        return (<SayMessageContainer/>);
    }
}

Which throws on <SayMessageContainer/>:

Property 'message' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes & IMessage & { children?: ReactElement...'.

How should this example be changed so that Connect can provide the props through mapStateToProps?

Note / possible hint: SayMessageContainer is typeof SayMessage, which seems off to me.

Typescript 2.0.0

Edit

Writing my own container seems to solve it, but I'd rather figure out how to do it properly using connect

class SayMessageContainer extends React.Component<{},{}>{
    render () {
        const props = mapStateToProps({});
        return (
            <SayMessage {...props}/>
        );
    }
}

Edit 2 Using the following typings:

"react-redux": "registry:npm/react-redux#4.4.0+20160614222153", 
"react-router": "registry:npm/react-router#2.4.0+20160628165748", 
"react-router-redux": "registry:npm/react-router-redux#4.0.0+20160602212457",
"redux": "registry:npm/redux#3.0.6+20160214194820"
2
Which typings are you using? The ones in DefinitelyTyped or in npm? - E_net4 the curator
"react-redux": "registry:npm/react-redux#4.4.0+20160614222153", "react-router": "registry:npm/react-router#2.4.0+20160628165748", "react-router-redux": "registry:npm/react-router-redux#4.0.0+20160602212457", "redux": "registry:npm/redux#3.0.6+20160214194820" - Andrew Carreiro
According to the latest typings, the outcome of connect(...) (wrapWithConnect) is a function with prototype T -> T (with T extends React.ComponentConstructor<any>), making the resulting component constructor expect the same set of props regardless of what the connector wrapper does. While this issue isn't resolved, you may have to handle it manually. See also this issue: github.com/reactjs/react-redux/issues/290 - E_net4 the curator
Also, please consider moving that comment to the actual question, since it's quite relevant. - E_net4 the curator

2 Answers

4
votes

You have to create an interface for each type of props and then pass it to the connect method :

// Regular props
interface OwnProps {}

// Props from the mapStateToProps method
interface StateProps {
    message: string;
}

// Props from the mapDispatchToProps method
interface DispatchProps {}

To create your component, you can use a specific type :

type SayMessageProps = OwnProps & StateProps & DispatchProps;

class SayMessage extends React.Component<SayMessageProps, {}>{
    render () {
        return (<div>{this.props.message}</div>);
    }
}

Then when using connect :

connect<StateProps, DispatchProps, OwnProps>(mapStateToProps)(SayMessage);

(you can also use {} instead of empty interfaces)

1
votes

What I do is type ownProps on either mapStateToProps or connect. If you had props you want the parent to send like -

interface IMyOwnProps{
   thing1;
   thing2;
}

then you can help TypeScript figure that out by calling connect like so...

const SayMessageContainer = connect<{}, {}, IMyOwnProps>(mapStateToProps)(SayMessage);

Typing ownProps on mapStateToProps is also sufficient. In your case, since you don't have any props, it might be sufficient to do the following, but I can't test it at the moment:

const SayMessageContainer = connect<{},{},{}>(mapStateToProps)(SayMessage);