如何在导入的反应组件上转换类型?
How to cast type on imported react component?
我希望能够做这样的事情:
import Form as React.Component<IFormProps> from './Form';
这样我就可以使用该组件,它需要 IFormProps 接口中定义的道具。
我正在尝试这样做,因为我的表单组件使用 redux-form
和 redux
,而这两个装饰器对我来说根本不起作用。我花了太多时间在谷歌上搜索有关如何执行此操作的示例,但没有任何效果。这是我的表单导出的样子,因为其他都不起作用。
export default connect(
mapStateToProps,
mapDispatchToProps,
)((reduxForm as any)(formConfig)(Form)) as any;
真的不应该这么难,我的 Form 组件中有一个 IFormProps 接口,我想要的只是让打字稿识别其中所需的道具。
编辑:
根据要求,我添加了更多关于我的组件外观的信息,但请注意,就打字而言,该组件相当复杂。我在让这些 connect 和 redux-form 装饰器工作时遇到了很多麻烦,我不得不做很多变通办法。而且浪费了很多时间。归根结底,我只需要组件根据 IFormProps 进行验证,我什至不关心装饰器是否不能一起工作。在这里或 google 在这方面似乎没有太多帮助。无论如何,下面有更多代码:
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>'.
如果我只将 any 留在 reduxForm 装饰器上,我会收到此错误。
TS2339: Property 'fields' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, ComponentState, any>> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'.
无论其价值如何,我都不希望任何人能够解决这些错误,因为发生的事情太多了。我自己也花了几个小时试图消除这些错误,这只是一场打地鼠游戏。
所以,在一天结束时,如果我能简单地覆盖 TS 认为导出的组件是什么,我会很高兴。
好的,我这样做了:
class Form extends Component<InjectedFormProps & IFromProps, {}> .....
然后像这样导出:
export default connect<{}, {}, IFromProps, {}>(
mapStateToProps,
mapDispatchToProps,
)(reduxForm(formConfig)(Form));
现在我的组件验证了正确的道具!
我希望能够做这样的事情:
import Form as React.Component<IFormProps> from './Form';
这样我就可以使用该组件,它需要 IFormProps 接口中定义的道具。
我正在尝试这样做,因为我的表单组件使用 redux-form
和 redux
,而这两个装饰器对我来说根本不起作用。我花了太多时间在谷歌上搜索有关如何执行此操作的示例,但没有任何效果。这是我的表单导出的样子,因为其他都不起作用。
export default connect(
mapStateToProps,
mapDispatchToProps,
)((reduxForm as any)(formConfig)(Form)) as any;
真的不应该这么难,我的 Form 组件中有一个 IFormProps 接口,我想要的只是让打字稿识别其中所需的道具。
编辑: 根据要求,我添加了更多关于我的组件外观的信息,但请注意,就打字而言,该组件相当复杂。我在让这些 connect 和 redux-form 装饰器工作时遇到了很多麻烦,我不得不做很多变通办法。而且浪费了很多时间。归根结底,我只需要组件根据 IFormProps 进行验证,我什至不关心装饰器是否不能一起工作。在这里或 google 在这方面似乎没有太多帮助。无论如何,下面有更多代码:
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>'.
如果我只将 any 留在 reduxForm 装饰器上,我会收到此错误。
TS2339: Property 'fields' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, ComponentState, any>> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'.
无论其价值如何,我都不希望任何人能够解决这些错误,因为发生的事情太多了。我自己也花了几个小时试图消除这些错误,这只是一场打地鼠游戏。
所以,在一天结束时,如果我能简单地覆盖 TS 认为导出的组件是什么,我会很高兴。
好的,我这样做了:
class Form extends Component<InjectedFormProps & IFromProps, {}> .....
然后像这样导出:
export default connect<{}, {}, IFromProps, {}>(
mapStateToProps,
mapDispatchToProps,
)(reduxForm(formConfig)(Form));
现在我的组件验证了正确的道具!