reactjs - How to cast type on imported react component?
问题描述
I want to be able to do something like this:
import Form as React.Component<IFormProps> from './Form';
So that I can then use the component and it will require the props defined in the IFormProps interface.
I am trying to do this, because my Form component uses redux-form
and redux
, and the two decorators, simply do not work for me. I've spend too much time googling for examples on how to do this, but nothing works. Here is what my Form export looks like, because nothing else works.
export default connect(
mapStateToProps,
mapDispatchToProps,
)((reduxForm as any)(formConfig)(Form)) as any;
It really shouldn't be this hard, I have a IFormProps interface inside my Form component, and all I want is for typescript to recognize the required props inside it.
EDIT: As requested I'm adding more info about what my component looks like, but BE WARNED the component is rather complex as far as typings goes. I've had so much trouble getting these connect and redux-form decorators to work, I've had to do a lot of workarounds. And it's wasted a lot of time. At the end of the day, I just need the component to validate against IFormProps, I don't even care if the decorators can't work together. There doesn't seem to be much help in this regard on here or google for that matter. Anyway, more code below:
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;
If I remove my any casts in the statements from the connect, this is the error I get:
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>'.
If I only leave the any on the reduxForm decorator, I get this error.
TS2339: Property 'fields' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, ComponentState, any>> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'.
For what its worth, I don't expect anyone to be able to resolve these errors, there's simply too much going on. And I myself have spent several hours trying to get rid of the errors, and it's just been a game of whack-a-mole.
So, at the end of the day, if I could simply overwrite what TS thinks the component exported is, I'll be happy.
解决方案
Ok I got it working by doing this:
class Form extends Component<InjectedFormProps & IFromProps, {}> .....
And then export like this:
export default connect<{}, {}, IFromProps, {}>(
mapStateToProps,
mapDispatchToProps,
)(reduxForm(formConfig)(Form));
Now my component validates for the correct props!
推荐阅读
- mongodb - 如何从本地连接 Heroku 上的 mlab mongoDB?
- javascript - 有没有办法在能够查看 HTML5 网站之前制作密码元素?
- numpy - 从 Pycharm 运行 numpy
- timeout - SPARQL wikidata 获取特定国家/地区所有城市的州/省
- python - 用pandas groupby求和值并重命名旧列?
- python - Mod_WSGI 找不到 python 模块
- python - Nan Value 的列被转换为浮点数
- java - java中的ArrayList中的异常
- r - 将单列拆分为四列并计算 R 中的重复模式
- java - 正则表达式从 html 标签中获取动态值