如何在导入的React组件上强制转换类型?

时间:2018-06-20 17:31:01

标签: reactjs typescript redux redux-form

我希望能够做这样的事情:

import Form as React.Component<IFormProps> from './Form';

这样我就可以使用组件了,它将需要在 IFormProps 界面中定义的道具。

我正在尝试执行此操作,因为我的Form组件使用redux-formredux,并且两个装饰器根本不适合我。我花了很多时间来搜索有关如何执行此操作的示例,但是没有任何效果。这是我的Form导出的样子,因为其他任何操作都无法完成。

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)((reduxForm as any)(formConfig)(Form)) as any;

真的不应该那么难,我在Form组件内部有一个IFormProps接口,我只想让打字稿识别其中的必需道具。

编辑: 根据要求,我将添加有关组件外观的更多信息,但请注意,就键入而言,组件相当复杂。要使这些连接和redux形式的装饰器正常工作,我遇到了很多麻烦,我不得不做很多解决方法。而且浪费了很多时间。归根结底,我只需要针对IFormProps进行验证的组件,我什至不在乎装饰器是否不能一起工作。对于这件事,在这里或谷歌上似乎在这方面没有太多帮助。无论如何,下面有更多代码:

Form.tsx

import * as React from 'react';
import {
  clearForm,
  doFormSubmit,
  getFormRelatedValues,
  IClearForm,
  IDoFormSubmit,
  IGetFormRelatedValues,
  ISearchFormRelatedValues,
  IUploadFile,
  searchFormRelatedValues,
  uploadFile,
} from '../actions/formActions';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { reduxForm, SubmissionError } from 'redux-form';

const { Component } = React;

function onSubmitFail(errors: IDCRA.IGenericObj,
  dispatch: IDCRA.IDispatch,
  submitError: IDCRA.IGenericObj,
  props: IFromProps) {
  // Something....
}

function scrollToFirstError() {
  // Something else....
}

const formConfig = {
  onSubmitFail: (
    errors: IDCRA.IGenericObj,
    dispatch: IDCRA.IDispatch,
    submitError: IDCRA.IGenericObj,
    props: IFromProps,
  ) => scrollToFirstError(errors, props),
  returnRejectedSubmitPromise: true,
  validate: someValidate,
};

declare interface IFromProps {
  // setFormWarningMessage?: (msg: string) => void;
  appContext?: string;
  asyncBlurFields?: string[];
  asyncValidate?: IAsyncValidate;
  change?: IDCRA.IChangeFieldValue;
  clearFormConnect?: IClearForm;
  doFormSubmitConnect?: IDoFormSubmit;
  error?: string;
  fields: { [key: string]: IDCRA.IField };
  firstPage: boolean;
  form: string;
  formObj: IDCRA.IForm;
  formPageIdentifier: string;
  getFormRelatedValuesConnect?: IGetFormRelatedValues;
  goToPrevPage?: () => any;
  handleSubmit?: (fn: (values: IDCRA.IGenericObj, dispatch: IDCRA.IDispatch) => any) => any;
  i18n?: IDCRA.IGenericObj;
  initialValues?: IDCRA.IGenericObj;
  invalid?: boolean;
  isCreateMode: boolean;
  lang: string;
  lastPage: boolean;
  onSubmitSuccess: (response: IDCRA.ISaveCardResponseObj) => any;
  ownerIdentifier: string;
  partialSave?: boolean;
  pristine?: boolean;
  rows: string[][];
  searchFormRelatedValuesConnect?: ISearchFormRelatedValues;
  submitButtonLabel?: string;
  submitFailed?: boolean;
  submitting?: boolean;
  untouch?: IDCRA.IUntouchField;
  uploadFileConnect?: IUploadFile;
  waitForEvent?: boolean;
}

class Form extends Component<IFromProps, {}> {
  constructor(props: IFromProps) {
    super(props);

    this.handleFormSubmit = this.handleFormSubmit.bind(this);
  }

  handleFormSubmit(values: IDCRA.IGenericObj, dispatch: IDCRA.IDispatch) {
    // Handles form submit....
  }

  render() {
    // Props are consumed here and used to build the form
    const {handleSubmit, identifier} = this.props;

    return (
      <div className="form" id={`form-container-${identifier}`}>
        <form onSubmit={handleSubmit(this.handleFormSubmit)}>
          <div className="card bg-default">

            {/* my form parts are here, not important */}

          </div>
        </form>
      </div>
    );
  }
}

function mapStateToProps(state: IDCRA.IAppState) {
  return {
    appContext: state.appCoreData.appCoreData.appContext,
    i18n: state.appCoreData.appCoreData.i18n,
  };
}

// I have to use my own dispatch type because by default I get errors...
// It's really hard to debug these deply nested TS errors, the messages are cryptic and could be coming from multple source
function mapDispatchToProps(dispatch: IDCRA.IDispatch) {
  return bindActionCreators(
    {
      // setFormWarningMessage,
      clearFormConnect: clearForm,
      doFormSubmitConnect: doFormSubmit,
      getFormRelatedValuesConnect: getFormRelatedValues,
      searchFormRelatedValuesConnect: searchFormRelatedValues,
      uploadFileConnect: uploadFile,
    },
    dispatch,
  );
}

//  Decorate the form component
export default connect(
  mapStateToProps,
  mapDispatchToProps,
)((reduxForm as any)(formConfig)(Form)) as any;

如果我从连接中删除语句中的 any 强制转换,这是我得到的错误:

TS2345: Argument of type 'typeof Form' is not assignable to parameter of type 'ComponentType<IFromProps & InjectedFormProps<{ [x: string]: any; }, IFromProps>>'.
  Type 'typeof Form' is not assignable to type 'StatelessComponent<IFromProps & InjectedFormProps<{ [x: string]: any; }, IFromProps>>'.
    Type 'typeof Form' provides no match for the signature '(props: IFromProps & InjectedFormProps<{ [x: string]: any; }, IFromProps> & { children?: ReactNode; }, context?: any): ReactElement<any>'.

如果我只在reduxForm装饰器上保留any,则会出现此错误。

TS2339: Property 'fields' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, ComponentState, any>> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'.

对于它的价值,我并不期望任何人能够解决这些错误,只是发生了太多的事情。我本人已经花了几个小时试图消除错误,这只是一场just鼠游戏。

因此,最终,如果我可以简单地覆盖TS认为导出的组件是什么,我会很高兴的。

1 个答案:

答案 0 :(得分:1)

好的,我这样做可以使它工作:

class Form extends Component<InjectedFormProps & IFromProps, {}> .....

然后像这样导出:

export default connect<{}, {}, IFromProps, {}>(
  mapStateToProps,
  mapDispatchToProps,
)(reduxForm(formConfig)(Form));

现在我的组件可以验证正确的道具了!