Typescript: почему Material-UI "withStyles ()" не работает с явным конструктором? - PullRequest
0 голосов
/ 01 октября 2018

Редактировать:

Обратите внимание, что IntelliJ IDEA сгенерировал неправильный конструктор.Теперь это исправлено, см .: https://youtrack.jetbrains.com/issue/WEB-35178


Я смотрю на использование Material-UI в моем приложении, но у меня возникли некоторые проблемы с решением для стилей withStyles в сочетании с TypeScript.

Я пытаюсь создать свой собственный маленький компонент-обертку, основываясь на документации Popper .

Проблема в том, что если я определяю конструктор явно так, как яЯ привык ((B) в приведенном ниже коде), затем эта строка:

export default withStyles(styles)(HelpComponent);

Дайте эту ошибку:

ERROR in [at-loader] ./src/main/ts/screen/keyword/HelpComponent.tsx:150:35 
    TS2345: Argument of type 'typeof HelpComponent' is not assignable to parameter of type 'ComponentType<never>'.
  Type 'typeof HelpComponent' is not assignable to type 'StatelessComponent<never>'.
    Type 'typeof HelpComponent' provides no match for the signature '(props: never, context?: any): ReactElement<any> | null'.

Единственный способ, которым я смог сделатьэта работа состоит в том, чтобы опустить явный конструктор и определить состояние как поле ((A) в приведенном ниже коде).

Есть ли способ объявить конструктор обычным способом, когда я использую withStyles?

Я на самом деле не возражаю устанавливать прямое состояние, как это, это немного менее шаблонно.Я отказываюсь от чего-либо, инициализируя состояние вне конструктора таким образом?

В конце концов, я просто не понимаю это сообщение об ошибке TypeScript - кто-нибудь может объяснить, что он пытается сказать?

import {
  createStyles,
  Paper,
  Popper,
  Theme,
  WithStyles,
  withStyles
} from '@material-ui/core';
import * as React from 'react';
import {ReactNode, SyntheticEvent} from 'react';
import {EventUtil} from "appUtil/EventUtil";
import {WarningSvg} from "component/svg-icon/WarningSvg";
let log = require("log4javascript").getLogger("HelpComponent");

export interface HelpComponentProps extends WithStyles<typeof styles> {
  children:ReactNode;
}

export interface HelpComponentState {
  open:boolean;
  arrowRef?: HTMLElement;
}

class HelpComponent extends React.Component<HelpComponentProps, HelpComponentState> {
  helpRef!: HTMLElement;

  // (A)
  state = {open: false, arrowRef: undefined};

  // (B)
  // constructor(props: HelpComponentProps, context: HelpComponentState){
  //   super(props, context);
  //   this.state = {open: false, arrowRef: undefined};
  // }

  handleClick = (event:SyntheticEvent<any>) => {
    EventUtil.stopClick(event);
    this.setState({open: !this.state.open,});
  };

  handleArrowRef = (node:HTMLElement) => {
    this.setState({
      arrowRef: node,
    });
  };

  render(){
    const {classes} = this.props;
    return <span ref={(ref)=>{if(ref) this.helpRef = ref}}>
      <WarningSvg onClick={this.handleClick}/>
      <Popper id={"help-popper"} className={classes.popper} transition
        open={this.state.open} anchorEl={this.helpRef}
        modifiers={{arrow:{enabled:true, element: this.state.arrowRef}}}
      >
        <span className={classes.arrow} ref={this.handleArrowRef}/>
        <Paper className={classes.paper}>{this.props.children}</Paper>
      </Popper>
    </span>;
  }

}

const styles = (theme: Theme) => createStyles({
  root: {
    flexGrow: 1,
  },
  scrollContainer: {
    height: 400,
    overflow: 'auto',
    marginBottom: theme.spacing.unit * 3,
  },
  scroll: {
    position: 'relative',
    width: '230%',
    backgroundColor: theme.palette.background.paper,
    height: '230%',
  },
  legend: {
    marginTop: theme.spacing.unit * 2,
    maxWidth: 300,
  },
  paper: {
    maxWidth: 400,
    overflow: 'auto',
  },
  select: {
    width: 200,
  },
  popper: {
    zIndex: 1,
    '&[x-placement*="bottom"] $arrow': {
      top: 0,
      left: 0,
      marginTop: '-0.9em',
      width: '3em',
      height: '1em',
      '&::before': {
        borderWidth: '0 1em 1em 1em',
        borderColor: `transparent transparent ${theme.palette.common.white} transparent`,
      },
    },
    '&[x-placement*="top"] $arrow': {
      bottom: 0,
      left: 0,
      marginBottom: '-0.9em',
      width: '3em',
      height: '1em',
      '&::before': {
        borderWidth: '1em 1em 0 1em',
        borderColor: `${theme.palette.common.white} transparent transparent transparent`,
      },
    },
    '&[x-placement*="right"] $arrow': {
      left: 0,
      marginLeft: '-0.9em',
      height: '3em',
      width: '1em',
      '&::before': {
        borderWidth: '1em 1em 1em 0',
        borderColor: `transparent ${theme.palette.common.white} transparent transparent`,
      },
    },
    '&[x-placement*="left"] $arrow': {
      right: 0,
      marginRight: '-0.9em',
      height: '3em',
      width: '1em',
      '&::before': {
        borderWidth: '1em 0 1em 1em',
        borderColor: `transparent transparent transparent ${theme.palette.common.white}`,
      },
    },
  },
  arrow: {
    position: 'absolute',
    fontSize: 7,
    width: '3em',
    height: '3em',
    '&::before': {
      content: '""',
      margin: 'auto',
      display: 'block',
      width: 0,
      height: 0,
      borderStyle: 'solid',
    },
  },
});

export default withStyles(styles)(HelpComponent);

Версии:

  • "машинопись":" 3.0.3 "
  • " @ types / реакции ":" 16.4.14 "
  • " @ types / реаги-дом ":" 16.0.7 "
  • "@ material-ui / core": "3.1.1"
  • "webpack": "4.19.1"

1 Ответ

0 голосов
/ 01 октября 2018

Если вы посмотрите на определение React.ComponentType:

type ComponentType<P = {}> = ComponentClass<P> | StatelessComponent<P>;

Альтернатива, которую вы пытаетесь использовать, - ComponentClass, которая определяется как:

interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
    new (props: P, context?: any): Component<P, S>;
    // ...
}

Уведомлениепараметр context является необязательным (отметка ?).Проблема в том, что параметр context вашего конструктора не является обязательным, поэтому HelpComponent не совместим с вызывающими программами, которые ожидают возможности пропустить аргумент context.Если вы сделаете параметр необязательным, ошибка должна исчезнуть.

Когда TypeScript сообщает об ошибке, что typeof HelpComponent нельзя присвоить типу объединения React.ComponentType, он полу-произвольно выбирает один член типа объединениясообщить подробную ошибку.К сожалению, он не выбрал тот, который вы намеревались, поэтому сообщение об ошибке не очень полезно.

На самом деле я не возражаю установить прямое состояние, как это, это немного менее шаблонно.Я отказываюсь от чего-либо, инициализируя состояние вне конструктора таким образом?

Да, переопределяя свойство state, вы можете непреднамеренно изменить его тип, чтобы он отличался от аргумента типа состояниячто вы перешли в базовый класс React.Component.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...