问题摘要:

在这个周末没有更改代码的情况下,一些类组件开始给我以下错误.

'EverySelector' cannot be used as a JSX component.
  Its element type 'ReactElement<any, any> | Component<Omit<EverySelectorProps, keyof WithTranslation>, any, any> | null' is not a valid JSX element.
    Type 'Component<Omit<EverySelectorProps, keyof WithTranslation>, any, any>' is not assignable to type 'Element | ElementClass | null'.
      Type 'Component<Omit<EverySelectorProps, keyof WithTranslation>, any, any>' is not assignable to type 'ElementClass'.
        The types returned by 'render()' are incompatible between these types.
          Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react-transition-group/node_modules/@types/react/index").ReactNode'.ts(2786)

并非每个类组件都是如此.我将在显示一些代码节中展示示例.

当让我的同事在他的一个老分支上做npm inpm run build时,它通过了,他没有任何错误.当我判断他的分支并做同样的操作时,它仍然会给我同样的错误.我清理了我的缓存,在他的分支上做了一个干净的安装.

我试过的

  1. I assumed that one of my packages is breaking me. So I removed all ^ from 包裹json: "redux": "^4.0.5" to "redux": "4.0.5". However the problem still persisted.
  2. 基于Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react-transition-group/node_modules/@types/react/index").ReactNode'.ts(2786),我开始玩@types/react@types/react-dom的版本.
  3. 玩弄出口.我注意到的第一个部件之一是<Header/>,它有以下输出
export default withRouter(
  connect(mapStateToProps, actions)(withStyles(styles)(withTranslation()(Header)))
);

我改成了

export default connect(mapStateToProps, actions)(withStyles(styles)(withTranslation()(Header)));

这使得<Header/>停止抛出错误,但我注意到许多其他类似的错误与withRouter无关,这让我相信问题与react-router-dom无关.之后,我收到的错误是index.tsx:

ReactDOM.render(
  <Provider store={store}>
    <HashRouter>
      <App style={{ width: '100%', height: '100%' }} />
    </HashRouter>
  </Provider>,
  document.getElementById('root')
);
'Provider' cannot be used as a JSX component.
  Its instance type 'Provider<AnyAction>' is not a valid JSX element.
    The types returned by 'render()' are incompatible between these types.
      Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react-transition-group/node_modules/@types/react/index").ReactNode'.
'HashRouter' cannot be used as a JSX component.
  Its instance type 'HashRouter' is not a valid JSX element.
    The types returned by 'render()' are incompatible between these types.
      Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react-transition-group/node_modules/@types/react/index").ReactNode'.ts(2786)

显示一些代码

这是一个损坏的组件EverySelector:

//EverySelector.tsx
import React, { ChangeEvent, Component, ReactNode } from 'react';
import { FormControl, InputLabel, MenuItem, Select, SelectChangeEvent } from '@mui/material';
import { WithTranslation, withTranslation } from 'react-i18next';

class EverySelector extends Component<EverySelectorProps> {
  private handleOnEveryChange = (event: SelectChangeEvent<number>, child: ReactNode): void => {
    event.target.value && this.props.onEveryChanged(event.target.value as number);
  };

  private generateDropdownOptions = (): number[] => {
    let options = [1, 2, 3, 5, 10, 15, 30, 60];
    const roundHoursToBeIncluded = [1, 2, 4, 8, 12, 24, 48];

    roundHoursToBeIncluded.map((roundHour: number) => {
      if ((roundHour * 60) % this.props.confEvery === 0) {
        const roundHourOption = (roundHour * 60) / this.props.confEvery;
        if (!options.includes(roundHourOption)) {
          options.push(roundHourOption);
        }
      }
    });

    return options.sort((a: number, b: number) => a - b);
  };

  private convertMinutesToString = (totalMinutes: number): string => {
    const days = Math.floor(totalMinutes / 1440); // 60 * 24
    const hours = Math.floor((totalMinutes - days * 1440) / 60);
    const minutes = Math.round(totalMinutes % 60);

    let output = '';

    if (days > 0) {
      output += days + ' ' + `${days === 1 ? this.props.t('day') : this.props.t('days')}`;
    }
    if (hours > 0) {
      output += `${days > 0 ? ' ' : ''}${hours} ${
        hours === 1 ? this.props.t('hour') : this.props.t('hours')
      }`;
    }
    if (minutes > 0) {
      output += `${days > 0 || hours > 0 ? ' ' : ''}${minutes} ${
        minutes === 1 ? this.props.t('minute') : this.props.t('minutes')
      }`;
    }

    return output;
  };

  public render(): React.ReactNode {
    return (
      <FormControl variant="outlined" size="small">
        <InputLabel>Every</InputLabel>
        <Select
          id="every_selector"
          value={this.props.every}
          onChange={this.handleOnEveryChange}
          fullWidth
          autoWidth
          label="Every"
        >
          {this.generateDropdownOptions().map((i: number) => (
            <MenuItem value={i}>{this.convertMinutesToString(this.props.confEvery * i)}</MenuItem>
          ))}
        </Select>
      </FormControl>
    );
  }
}

interface EverySelectorProps extends WithTranslation {
  confEvery: number;
  every: number;
  onEveryChanged: (every: number) => void;
}

export default withTranslation()(EverySelector);

这是一个工作部件DateSelectorAverage:

//DateSelectorAverage.tsx
import { Grid, TextField } from '@mui/material';
import moment from 'moment';
import React, { ChangeEvent, Component } from 'react';
import { connect } from 'react-redux';
import {
  AvgFromDatePeriodAction,
  AvgToDatePeriodAction,
} from '../../../state_management/actions/PeriodSelectionAction';
import { PeriodSelectionActionCreator } from '../../../state_management/actions/PeriodSelectionActionCreator';

class DateSelectorAvg extends Component<DateSelectorAvgProps> {
  public render(): React.ReactNode {
    return (
      <Grid container spacing={3} direction="row">
        <Grid item>
          <TextField
            label="Average From Date"
            type="date"
            size="small"
            variant="outlined"
            value={moment(this.props.avgFromDate).format('YYYY-MM-DD')}
            onChange={(event: ChangeEvent<HTMLInputElement>): void => {
              this.props.periodAvgFromDateChanged(new Date(event.target.value));
            }}
            InputLabelProps={{
              shrink: true,
            }}
          />
        </Grid>
        <Grid item>
          <TextField
            label="Average To Date"
            type="date"
            size="small"
            variant="outlined"
            value={moment(this.props.avgToDate).format('YYYY-MM-DD')}
            onChange={(event: ChangeEvent<HTMLInputElement>): void => {
              this.props.periodAvgToDateChanged(new Date(event.target.value));
            }}
            InputLabelProps={{
              shrink: true,
            }}
          />
        </Grid>
      </Grid>
    );
  }
}

interface DateSelectorAvgProps extends DateSelectorAvgOwnProps, StateProps, DispatchProps {}

interface DateSelectorAvgOwnProps {}

interface StateProps {
  avgFromDate: Date;
  avgToDate: Date;
}

interface DispatchProps {
  periodAvgFromDateChanged: (date: Date | null) => AvgFromDatePeriodAction;
  periodAvgToDateChanged: (date: Date | null) => AvgToDatePeriodAction;
}

const mapStateToProps = (stateProps: { period: StateProps }): StateProps => ({
  avgFromDate: stateProps.period.avgFromDate,
  avgToDate: stateProps.period.avgToDate,
});

const mapDispatchToProps: DispatchProps = {
  periodAvgFromDateChanged: PeriodSelectionActionCreator.changeAvgFromDate,
  periodAvgToDateChanged: PeriodSelectionActionCreator.changeAvgToDate,
};

export default connect(mapStateToProps, mapDispatchToProps)(DateSelectorAvg);

包裹json

{
  "name": "device-counter-collector-gui",
  "version": "0.1.1-SNAPSHOT",
  "private": true,
  "devDependencies": {
    "@types/chart.js": "2.9.32",
    "@types/googlemaps": "3.30.16",
    "@types/jest": "26.0.19",
    "@types/lodash": "4.14.171",
    "@types/markerclustererplus": "2.1.33",
    "@types/node": "14.14.16",
    "@types/react": "17.0.39",
    "@types/react-dom": "17.0.11",
    "@types/react-redux": "7.1.14",
    "@types/react-router-dom": "5.1.6",
    "@typescript-eslint/eslint-plugin": "4.11.1",
    "@typescript-eslint/parser": "4.11.1",
    "eslint-config-prettier": "7.1.0",
    "eslint-plugin-prettier": "3.3.0",
    "eslint-plugin-react": "7.21.5",
    "prettier": "2.2.1",
    "react-router-prop-types": "1.0.5",
    "redux-devtools-extension": "2.13.5"
  },
  "dependencies": {
    "@date-io/date-fns": "1.3.13",
    "@emotion/react": "11.7.1",
    "@emotion/styled": "11.6.0",
    "@mui/icons-material": "5.4.2",
    "@mui/lab": "5.0.0-alpha.69",
    "@mui/material": "5.4.2",
    "@mui/styles": "5.4.2",
    "acorn-jsx": "5.0.0",
    "axios": "0.14.0",
    "chart.js": "2.9.4",
    "chartjs-plugin-zoom": "0.7.7",
    "colorbrewer": "1.0.0",
    "date-fns": "2.28.0",
    "dotenv-cli": "4.1.0",
    "eslint": "7.17.0",
    "formik": "2.2.9",
    "i18next": "21.6.12",
    "i18next-browser-languagedetector": "3.0.1",
    "jwt-decode": "2.2.0",
    "lodash": "4.17.21",
    "material-ui-popup-state": "1.0.1",
    "moment": "2.18.1",
    "moment-timezone": "0.5.33",
    "node-polyfill-webpack-plugin": "1.1.4",
    "path-browserify": "1.0.1",
    "path-to-regexp": "1.7.0",
    "pondjs": "0.8.5",
    "react": "17.0.2",
    "react-autobind": "1.0.6",
    "react-bootstrap": "0.32.4",
    "react-bootstrap-table": "4.3.1",
    "react-chartjs-2": "2.11.1",
    "react-device-detect": "2.0.1",
    "react-dom": "16.8.6",
    "react-easy-chart": "1.0.0",
    "react-file-download": "0.3.3",
    "react-flexbox-grid": "1.0.2",
    "react-ga": "3.3.0",
    "react-google-maps": "9.4.5",
    "react-google-maps-loader": "4.2.3",
    "react-i18next": "11.15.5",
    "react-icons": "4.3.1",
    "react-jss": "8.6.1",
    "react-recaptcha-google": "1.1.1",
    "react-redux": "7.1",
    "react-router-dom": "5.3.0",
    "react-scripts": "5.0.0",
    "react-select": "1.0.0-rc.2",
    "react-timeseries-charts": "0.15.5",
    "redux": "4.0.5",
    "redux-thunk": "2.2.0",
    "typescript": "4.5.2",
    "uuid": "2.0.3",
    "webpack": "4.44.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "lint": "eslint . --ext .js --ext .ts --ext .tsx",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "proxy": "http://localhost:8080",
  "homepage": "./",
  "module": {
    "noParse": "./~/object-hash/dist/object_hash.js"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

推荐答案

我更新了react&;react-dom

npm i react@18 react-dom@18 @types/react@18 @types/react-dom@18

Typescript相关问答推荐

映射类型中和映射类型之间的通用变量推断

如果存在一处房产,请确保存在其他房产

如何使用另一个类型的属性中的类型

如何使用Generics保留构造函数的类型信息?

如何基于对象关键字派生类型?

有没有办法适当缩小类型?

如何从TypScript中的接口中正确获取特定键类型的所有属性?

angular 17独立使用多个组件(例如两个组件)

React重定向参数

接口中函数的条件参数

如何消除在Next.js中使用Reaction上下文的延迟?

TypeError:正文不可用-NextJS服务器操作POST

TypeScrip:从对象中提取和处理特定类型的键

为什么S struct 类型化(即鸭子类型化)需要非严格类型联合?

如何通过属性名在两个泛型数组中找到匹配的对象?

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

如何键入派生类的实例方法,以便它调用另一个实例方法?

如何正确键入泛型相对记录值类型?

将带有额外id属性的Rust struct 展平回TypeScript单个对象,以返回wasm-bindgen函数

带有过滤键的 Typescript 映射类型