将Redux-Form与React-Redux连接使用时出现TypeScript错误

时间:2017-09-28 20:40:23

标签: reactjs typescript redux react-redux redux-form

我爱上了TypeScript,直到我发现Redux-Form与React-Redux之间存在一些非常令人沮丧的不兼容性。

我的目标是使用react-redux reduxForm装饰器包裹connect装饰组件 - 这种模式在babel配置中一直对我有用,并且似乎遵循HOC方法。这是一个例子:

import * as React from 'react';
import { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { reduxForm, Field, InjectedFormProps } from 'redux-form';

interface SampleFormData {
  username: string;
}

interface SampleFormProps {
  saveData: (data: SampleFormData) => void;
}

type AllSampleFormProps = SampleFormProps & InjectedFormProps<SampleFormData>;

const SampleForm: React.SFC<AllSampleFormProps> = (props) => (
  <form onSubmit={props.handleSubmit(props.saveData)}>
    <Field name="username" component="input" />
  </form>
);

const DecoratedSampleForm = reduxForm<SampleFormData>({ form: "sampleForm" })(SampleForm);

export default connect(
  () => ({}),
  (dispatch) => ({
    saveData: (data: SampleFormData) => dispatch({ type: "SAVE_DATA", data })
  })
)(DecoratedSampleForm);

这是TypeScript抛出的错误:

> Argument of type 'DecoratedComponentClass<SampleFormData,
> Partial<ConfigProps<SampleFormData, {}>>>' is not assignable to
> parameter of type 'ComponentType<{ saveData: (data: SampleFormData) =>
> { type: string; data: SampleFormData; }; }>'.
> 
> Type 'DecoratedComponentClass<SampleFormData,
> Partial<ConfigProps<SampleFormData, {}>>>' is not assignable to type
> 'StatelessComponent<{ saveData: (data: SampleFormData) => { type:
> string; data: SampleFormData; };...'.
> 
> Type 'DecoratedComponentClass<SampleFormData,
> Partial<ConfigProps<SampleFormData, {}>>>' provides no match for the
> signature '(props: { saveData: (data: SampleFormData) => { type:
> string; data: SampleFormData; }; } & { children?: ReactNode; },
> context?: any): ReactElement<any>'.

有没有人找到让react-redux接受DecoratedComponentClass类型的解决方案?我找到一个suggestion来使用&#34;中间&#34;组件,但我还没有设法让这与thunk行动一起工作。此外,我发现在输入表格的道具方面,这会产生的问题多于解决的问题。

2 个答案:

答案 0 :(得分:9)

对于遇到此问题的任何人,我发现通过为connect语句提供空TStatePropsTDispatchProps对象,我能够解除错误。

interface SampleFormData {
  username: string;
}

interface SampleFormProps {
  saveData: (data: SampleFormData) => void;
}

type AllSampleFormProps = SampleFormProps & InjectedFormProps<SampleFormData>;

const SampleForm: React.SFC<AllSampleFormProps> = (props) => (
  <form onSubmit={props.handleSubmit(props.saveData)}>
    <Field name="username" component="input" />
  </form>
);

const DecoratedSampleForm = reduxForm<SampleFormData>({ form: "sampleForm" })(SampleForm);

export default connect<{},{}>(
  () => ({}),
  (dispatch) => ({
    saveData: (data: SampleFormData) => dispatch({ type: "SAVE_DATA", data })
  })
)(DecoratedSampleForm);

这样做的一个缺点是它迫使我们盲目地提供连接道具,但我觉得这比写一个覆盖@types声明更优雅。

为了解决这个缺点,我能够通过提供正确的接口与空对象的连接来验证类型;但是,此方法只能临时完成,以检查绑定,因为它无法解决DecoratedComponentClass错误。

export default connect<{}, SampleFormProps, InjectedFormProps<SampleFormData>>(
  () => ({}),
  (dispatch) => ({
    saveData: (data: SampleFormData) => dispatch({ type: "SAVE_DATA", data })
  })
)(DecoratedSampleForm);

答案 1 :(得分:1)

更高的Component Interface声明完成了将连接类型与组件状态连接起来并使用装饰器支持Type的技巧。

connect.ts

import * as React from "react";
import {
  connect as originalConnect,
  MapStateToPropsParam,
  MergeProps,
  Options
} from "react-redux";
import { IState } from "./index";

export interface IDisPatchProps {
  [key: string]: () => void;
}

export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
  TComponent extends React.ComponentType<TInjectedProps & TNeedsProps>
>(
  component: TComponent
) => TComponent;

export interface IConnectProps {
  <TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
    mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, IState>,
    mapDispatchToProps?: IDisPatchProps
  ): InferableComponentEnhancerWithProps<
    TStateProps & TDispatchProps,
    TOwnProps
  >;

  <TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}>(
    mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, IState>,
    mapDispatchToProps?: IDisPatchProps,
    mergeProps?: MergeProps<
      TStateProps,
      TDispatchProps,
      TOwnProps,
      TMergedProps
    >,
    options?: Options<TStateProps, TOwnProps, TMergedProps>
  ): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
}

declare module "react-redux" {
  // tslint:disable-next-line
  interface Connect extends IConnectProps {}
}

export const connect = originalConnect as IConnectProps;


 ***ClassFile***

 @connect(
  (state: IState): IStateProps => ({
    count: state.counter.count,
    isLoading: state.counter.isLoading
  }),
  {
    decrement,
    increment
  }
)
export default class MyApp

链接: https://github.com/TomasHubelbauer/react-redux-typescript-connect-decorator-demo/blob/master/my-app/src/connect.ts

贷方转到: TomasHubelbauer https://github.com/TomasHubelbauer