如何与打字稿反应向样式化的Material-UI道具类添加属性

时间:2018-08-23 20:43:18

标签: reactjs typescript material-ui

我想使用material-ui,同时使用react和Typescript。我想将属性传递给组件,但无法弄清楚该怎么做。我正在使用material-UI存储库中的react-typescript示例。我尝试的方法如下:

添加属性界面:

const styles = (theme: Theme) =>
  createStyles({
    root: {
      textAlign: 'center',
      paddingTop: theme.spacing.unit * 20,
    },
  });

interface IndexProps
  extends WithStyles<typeof styles> {
  myText: string;
}

然后定义我的组件,并使用属性:

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));

在“索引”页面上,我输入:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Index from './pages/index';

ReactDOM.render(<Index myText="Foo" />, document.querySelector('#root'));

但是出现编译错误:

(5,18): Type '{ myText: string; }' has no properties in common with type 'IntrinsicAttributes'.

我在这里做错了什么?任何帮助将不胜感激

为完整起见,我的packages.json文件是:

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

1 个答案:

答案 0 :(得分:1)

我假设您正在使用this definition of withRoot。如果将鼠标悬停在对withRoot的呼叫上,则会看到其返回类型为:

(props: object) => JSX.Element

这是错误的:道具类型应为{myText: string},而不是object。如果转到withRoot的定义,您将看到它的来源:

function withRoot(Component: React.ComponentType) {
  function WithRoot(props: object) {

这些行应替换为:

function withRoot<P>(Component: React.ComponentType<P>) {
  function WithRoot(props: P) {

您可以考虑在原始示例中发送拉取请求以解决此问题。

第二回合

(请参阅注释中的示例)

事实证明这与根本原因无关。我在src/App.tsx第60行看到了错误:

let drawer = <ItemsList myText="asdf" history={history} />;

请参考src/components/ItemsList.tsx底部的定义:

export default withStyles(styles)<{}>(connect(mapStateToProps)(withWidth()(ItemsList))
);

对于初学者,请摆脱该显式类型参数<{}>,该参数将覆盖自动确定的所有参数;令我惊讶的是,它本身并没有给您带来任何错误。然后App.tsx中的错误变为location道具丢失。您可能已经认识到它是RouteComponentProps之一,但是我没有,所以我通过将以下内容添加到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)

不幸的是,这些复杂的类型操作导致类型表达式难以理解,甚至在悬停弹出窗口中被截断,所以我发现查看所有道具的最佳方法是查看完成菜单,如下指示。然后,我们看到四个意外的道具:historylocationmatchstaticContext。如果我们查看这些来源可能来自的所有地方,希望它们可以被识别为来自ItemsList.Props extends RouteComponentProps<void>。确实,该声明是错误的,因为您没有使用ItemsList作为路线组件,也没有手动传递所有这些道具,ItemsList实际上也没有使用除history之外的任何道具。您再次声明(并通过)。因此,只需从扩展列表中删除RouteComponentProps<void>

我们已经看到,使用包装好的React组件时发生类型错误可能有许多不同的原因。希望我对您有所了解,您自己也可以找到此类错误。