typescript “Readonly<{}>”类型上不存在“ValueChanging”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46322511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:54:13  来源:igfitidea点击:

'ValueChanging' does not exist on type 'Readonly<{}>'

reactjstypescript

提问by Ian Klinck

I'm trying to implement a handler, in React, for a survey implemented in SurveyJS. This is for multiple-choice questions that may have answers like "None of the Above" or "Prefer Not To Answer". If one of those answers is selected, all other answers should be blanked out, and if a different answer is selected, these checkboxes should be cleared out. I'm doing fine with either one of these individually, but having problems with a question where both options are present, specifically when switching back & forth between the two special options.

我正在尝试在 React 中实现一个处理程序,用于在 SurveyJS 中实现的调查。这适用于可能有“以上都不是”或“不愿回答”等答案的多项选择题。如果选择了其中一个答案,则所有其他答案都应被清除,如果选择了不同的答案,则应清除这些复选框。我对这两个选项中的任何一个都做得很好,但是在两个选项都存在的问题上遇到了问题,特别是在两个特殊选项之间来回切换时。

What I think is happening is that when one answer triggers the handler, and unchecks the other checkbox, it triggers the handler again. My solution is to set a state that indicates when the handler is in the middle of this process, and not do it again at that time.

我认为正在发生的是,当一个答案触发处理程序并取消选中另一个复选框时,它会再次触发处理程序。我的解决方案是设置一个状态,指示处理程序何时处于此过程的中间,并且此时不再执行此操作。

I got a JS solution for this here: https://github.com/surveyjs/editor/issues/125- and below is my attempt to convert it to React. (Just the relevant parts of the code included.)

我在这里得到了一个 JS 解决方案:https: //github.com/surveyjs/editor/issues/125- 下面是我将它转换为 React 的尝试。(仅包含代码的相关部分。)

However, on compile, it gives the following error:

但是,在编译时,它会出现以下错误:

ERROR in [at-loader] ./src/components/Survey/SurveyContainer.tsx:55:19 TS2339: Property 'ValueChanging' does not exist on type 'Readonly<{}>'.

[at-loader] ./src/components/Sur​​vey/SurveyContainer.tsx:55:19 TS2339 中的错误:“Readonly<{}>”类型上不存在“ValueChanging”属性。

I can't find anything about this specific error. Other references to the state (i.e. where I'm setting it) are working. Why can't I read it?

我找不到有关此特定错误的任何信息。对状态的其他引用(即我设置它的位置)正在工作。为什么我读不出来?

Thanks!

谢谢!

Component:

零件:

import * as React from 'react';
import { Component } from 'react';
import { Survey, surveyStrings } from 'survey-react';
import 'whatwg-fetch';
import Marked from '../Marked';
import * as style from './style';

interface Props {
  surveyJson: object;
  complete: boolean;
  resultMarkdown: string;
  surveyTitle: string;
  sendSurveyAnswers: (answers: object[]) => void;
  noneOfTheAboveHandler: (survey: object, options: object) => void;
}

Survey.cssType = 'standard';
surveyStrings.progressText = '{0}/{1}';
surveyStrings.emptySurvey = '';

export default class SurveyComponent extends Component<Props, {}> {
  render() {
    const { surveyJson, sendSurveyAnswers, complete, surveyTitle, resultMarkdown, noneOfTheAboveHandler } = this.props;
    return (
      <style.Wrapper>
         { surveyJson && (!complete) &&
          <style.SurveyWrapper>
            <style.SurveyTitle>{ surveyTitle }</style.SurveyTitle>
            <style.Survey>
              <Survey
                onValueChanged={ noneOfTheAboveHandler }
                css={ style.surveyStyles }
                json={ surveyJson }
                onComplete={ sendSurveyAnswers }
              />
            </style.Survey>
          </style.SurveyWrapper>
         }
         { complete &&
         <style.Results>
           <Marked content={resultMarkdown} />
         </style.Results>
         }
      </style.Wrapper>
    );
  }
}

Container:

容器:

import * as React from 'react';
import { Component } from 'react';
import { connect } from 'react-redux';
import SurveyComponent from './SurveyComponent';

interface Props {
  id: string;
  surveyJson: object;
  complete: boolean;
  resultMarkdown: string;
  surveyTitle: string;
  getSurveyQuestions: (id: string) => void;
  sendSurveyAnswers: (answers: object[]) => void;
  noneOfTheAboveHandler: (survey: object, options: object) => void;
  clearSurvey: () => void;
}

class SurveyContainer extends Component<Props, {}> {
  constructor(props) {
    super(props);
    this.state = { ValueChanging: false };
  }

  componentDidMount() {
    this.noneOfTheAboveHandler = this.noneOfTheAboveHandler.bind(this);
    this.props.getSurveyQuestions(this.props.id);
  }

  specialValueSelected(options, specialValue) {
    const { question } = options;
    const prevValue = question.prevValue;
    const index = options.value.indexOf(specialValue);
    this.setState({ ValueChanging: true });
    //has special value selected
    if(index > -1) {
      //special value was selected before
      if(prevValue.indexOf(specialValue) > -1) {
        var value = question.value;
        value.splice(index, 1);
        question.value = value;
      } else {
        //special value select just now
        question.value = [specialValue];
      }
    }
    this.setState({ ValueChanging: false });
    return index > -1;
  }

  noneOfTheAboveHandler(survey, options) {
    const none = 'NA';
    const preferNotToAnswer = 'PN';
    const { question } = options;

    if(this.state.ValueChanging) {
      return;
    }

    if (!question || question.getType() !== 'checkbox') {
      return;
    }

    if (!question.prevValue || !options.value) {
      question.prevValue = options.value;
      return;
    }

    if (!this.specialValueSelected(options,none)) {
      this.specialValueSelected(options,preferNotToAnswer);
    }

    question.prevValue = options.value;
  }

  componentWillUnmount() {
    this.props.clearSurvey();
  }

  render() {
    return (
      <SurveyComponent
        noneOfTheAboveHandler={this.noneOfTheAboveHandler}
        {...this.props}
      />
    );
  }
}

const mapStateToProps = (state, ownProps) => ({
  surveyJson: state.survey.json,
  answers: state.survey.answers,
  resultMarkdown: state.survey.resultMarkdown,
  complete: state.survey.complete,
  surveyTitle: state.page && state.page.data ? state.page.data.title : ''
});

const mapDispatchToProps = dispatch => ({
  getSurveyQuestions: id => dispatch({ type: 'GET_SURVEY_QUESTIONS', id }),
  sendSurveyAnswers: answers => dispatch({ type: 'SEND_SURVEY_ANSWERS', answers: answers.data }),
  clearSurvey: () => dispatch({ type: 'CLEAR_SURVEY' })
});

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

回答by Oblosys

The most likely cause for this is that you don't specify the type for your component's state in its class definition, so it defaults to {}. You can fix it by declaring interfaces for the types of props and state and providing these as type arguments to React.Component:

最可能的原因是您没有在其类定义中指定组件状态的类型,因此它默认为{}. 您可以通过声明 props 和 state 类型的接口并将它们作为类型参数提供给 React.Component 来修复它:

interface MyComponentProps { /* declare your component's props here */ }
interface MyComponentState { ValueChanging :  boolean }

class MyComponent extends React.Component<MyComponentProps, MyComponentState> {
  constructor(props) {
  ...

You could provide the types directly between the <and >, but using interfaces usually leads to more readable code and promotes reuse. To prevent confusion with components it's also a good idea to use lower-case identifiers for the properties on props and state.

您可以直接在<和之间提供类型>,但使用接口通常会导致代码更具可读性并促进重用。为了防止与组件混淆,对 props 和 state 上的属性使用小写标识符也是一个好主意。

回答by Andrew Telnov

FYI: We have introduce this functionality into SurveyJS Library sometimes ago.

仅供参考:我们有时已将此功能引入到 SurveyJS 库中。

Here is the react examplewith "Select All" and "None of the Above" features, out of the box, without custom code.

这是具有“全选”和“以上都不是”功能的反应示例,开箱即用,没有自定义代码。

Thank you!

谢谢!