Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
68
rated 0 times [  71] [ 3]  / answers: 1 / hits: 31393  / 7 Years ago, fri, november 3, 2017, 12:00:00

I try to build a react app in typescript using redux and react-router-dom. I ran into typing issues when I added redux to my app. Thus I created the following minimal example with only one page test-page:



App.jsx



import * as React from 'react';
import { Route, Redirect } from 'react-router-dom'
import Test from './containers/test-page'
import './App.css';

class App extends React.Component {
render() {
return (
<div className=ui container id=main>
<Route exact path=/ render={() => <Redirect to=/test />}/>
<Route exact path=/test component={Test} />
</div>
);
}
}

export default App;


The container for the test page looks like this. It produces a typing error in the call to connect.



containers/test-page/index.tsx



import { Dispatch } from 'redux'
import { connect } from 'react-redux'
import TestPage from './test-page'

function mapDispatchToProps(dispatch: Dispatch<any>) {
return dispatch({ type: 'ALERT_USER' });
}

function mapStateToProps(state: any) {
return { label: 'my test label' }
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(TestPage)


The container uses the following react component, which in production should render a page for the router. It produces two errors, see below.



containers/test-page/test-page.tsx



import * as React from 'react';

export namespace Test {
export interface Props {
alert: () => void;
label: string;
}

export interface State {
}
}

export default class TestPage extends React.Component {

constructor(props?: Test.Props, state?: Test.State, context?: any) {
super(props, context);
}

sendAlert = () => {
this.props.alert()
}

render() {
return (
<div>
<h1>Test</h1>
<button onClick={this.sendAlert}>{this.props.label}</button>
</div>
);
}
}


Error messages:



proxyConsole.js:54 ./src/containers/test-page/test-page.tsx
(20,18): error TS2339: Property 'alert' does not exist on type 'Readonly<{ children?: ReactNode; }> & Readonly<{}>'.

proxyConsole.js:54 ./src/containers/test-page/test-page.tsx
(27,54): error TS2339: Property 'label' does not exist on type 'Readonly<{ children?: ReactNode; }> & Readonly<{}>'.

proxyConsole.js:54 ./src/containers/test-page/index.tsx
(16,3): error TS2345: Argument of type 'typeof TestPage' is not assignable to parameter of type 'ComponentType<{ label: string; } & { type: string; }>'.
Type 'typeof TestPage' is not assignable to type 'StatelessComponent<{ label: string; } & { type: string; }>'.
Type 'typeof TestPage' provides no match for the signature '(props: { label: string; } & { type: string; } & { children?: ReactNode; }, context?: any): ReactElement<any> | null'.


I tried to follow different guides and looked up example implementations but could not solve these issues. I do not understand the error messages of the typescript compiler:




  • Why do my properties not exist on this.props when I defined them?

  • What exactly is not assignable in connect?


More From » reactjs

 Answers
49

A couple of things I notice:



1) As far as I've seen in examples and when working with props in TypeScript, your call to React.Component needs to specify Props as a type argument like so:



export default class TestPage extends React.Component<Test.Props, Test.State>{

constructor(props: Test.Props) {
super(props);
}

}


You can specify that your component does not accept props or state by passing empty interfaces i.e.:



export default class TestPage extends React.Component<{}, {}>{

// constructor becomes 'useless' at this point and is not needed
constructor() {
super();
}

}


I think this explains why your call signature is not matching and why there are no properties visible on this.props - TS sees an interface of ReadOnly{} since it has no type arguments passed in.



2) Your mapStateToProps function doesn't look quite right. mapStateToProps takes two arguments, state (referencing your Redux store) and ownProps as an optional second argument, which refers to props passed down from the parent. So mapStateToProps should look like this:



function mapStateToProps(state: any, ownProps: { label: string }) {

return {
label: ownProps.label
};
}


This is my guess for why connect is throwing an error - it is simply a place where you make assertions about how Redux should handle combining props coming from the store and props coming from the parent. Let me know if this works out.


[#56018] Wednesday, November 1, 2017, 7 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
erinh

Total Points: 38
Total Questions: 100
Total Answers: 110

Location: Macau
Member since Mon, Nov 16, 2020
4 Years ago
;