Reputation: 195
I am wanting to use material-ui, using react and typescript. I would like to pass properties to the components, but cannot figure out how to do it. I am using the react-typescript example from the material-UI repo. What I tried is as follows:
Add a properties interface:
const styles = (theme: Theme) =>
createStyles({
root: {
textAlign: 'center',
paddingTop: theme.spacing.unit * 20,
},
});
interface IndexProps
extends WithStyles<typeof styles> {
myText: string;
}
then define my component, and use the property:
class Index extends React.Component<IndexProps> {
render() {
return (
<div className={this.props.classes.root}>
<Typography variant="display1" gutterBottom>
Material-UI
</Typography>
<Typography variant="subheading" gutterBottom>
example project text=[{this.props.myText}]
</Typography>
<Button variant="raised" color="secondary" >
Super Secret Password
</Button>
</div>
);
}
}
export default withRoot(withStyles(styles)(Index));
On my Index page I put:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Index from './pages/index';
ReactDOM.render(<Index myText="Foo" />, document.querySelector('#root'));
But get a compile error:
(5,18): Type '{ myText: string; }' has no properties in common with type 'IntrinsicAttributes'.
What am I doing wrong here? Any help would be greatly appreciated
For completeness, my packages.json
file is:
{
"name": "create-react-app-with-typescript",
"version": "0.1.0",
"private": true,
"main": "src/index.tsx",
"dependencies": {
"@material-ui/core": "latest",
"@types/react": "*",
"@types/react-dom": "*",
"react": "latest",
"react-dom": "latest",
"react-scripts-ts": "latest"
},
"devDependencies": {
"@types/jest": "*",
"@types/node": "*",
"typescript": "latest"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
}
}
Upvotes: 0
Views: 2949
Reputation: 30879
I'm assuming that you are using this definition of withRoot
. If you hover over the call to withRoot
, you'll see its return type is:
(props: object) => JSX.Element
This is wrong: the props type should be {myText: string}
, not object
. If you go to the definition of withRoot
, you'll see where this is coming from:
function withRoot(Component: React.ComponentType) {
function WithRoot(props: object) {
Those lines should be replaced with:
function withRoot<P>(Component: React.ComponentType<P>) {
function WithRoot(props: P) {
You could consider sending a pull request to fix this in the original example.
(Referring to the example in the comment)
This turns out to have an unrelated root cause. I see the error on src/App.tsx
line 60:
let drawer = <ItemsList myText="asdf" history={history} />;
referring to the definition at the bottom of src/components/ItemsList.tsx
:
export default withStyles(styles)<{}>(connect(mapStateToProps)(withWidth()(ItemsList))
);
For starters, get rid of that explicit type argument <{}>
, which is overriding whatever is being determined automatically; I'm surprised that didn't give you an error by itself. Then the error in App.tsx
changes to say that the location
prop is missing. You might already recognize this as one of the RouteComponentProps
, but I didn't, so I proceeded to look at the entire set of props of the final component by adding the following to ItemsList.tsx
:
type PropsOf<C> = C extends React.ComponentType<infer P> ? P : never;
const ItemsListWrapped = withStyles(styles)(connect(mapStateToProps)(withWidth()(ItemsList));
type FinalProps = PropsOf<typeof ItemsListWrapped>;
let x: FinalProps;
x. // look at completion menu here (Ctrl-Space in Visual Studio Code)
Unfortunately, these complicated type operations give rise to type expressions that are hard to understand or even get truncated in the hover pop-up, so the best way I found to see all the props was to look at the completion menu, as indicated. Then we see four unexpected props: history
, location
, match
, and staticContext
. If we look at all the places these might have come from, hopefully they are recognizable as coming from the ItemsList.Props extends RouteComponentProps<void>
. Indeed, that declaration is wrong because you are not using ItemsList
as a route component nor manually passing all of those props, nor does ItemsList
actually use any of the props except for history
, which you declare again (and do pass). So just remove RouteComponentProps<void>
from the extends list.
As we've seen, type errors on using a wrapped React component can have many different causes. I hope I've given you some sense of how to track down future such errors yourself.
Upvotes: 2