reactjs - 如何正确输入 Redux 连接调用?

标签 reactjs typescript redux connect

我正在尝试将 Redux 状态存储与 TypeScript 结合使用。我正在尝试使用 Redux 的官方类型,并希望对 connect 方法进行整个调用(连接 mapStatetoPropsmapDispatchToProps 与一个组件)类型安全。

我经常看到方法 mapStatetoPropsmapDispatchToProps 只是自定义类型并返回部分组件 Prop ,例如:

function mapStateToProps(state: IStateStore, ownProps: Partial<IComponentProps>)
  : Partial<IProjectEditorProps> {}
function mapDispatchToProps (dispatch: Dispatch, ownProps: Partial<IComponentProps>)
  : Partial<IProjectEditorProps> {}

这是类型化的并且可以工作,但并不真正安全,因为可能会实例化一个缺少 props 的组件,因为 Partial 接口(interface)的使用允许不完整的定义。但是,这里需要 Partial 接口(interface),因为您可能想在 mapStateToPropsmapDispatchToProps 中定义一些 Prop ,而不是在一个函数中全部定义。所以这就是为什么我想避免这种风格。

我目前正在尝试使用的是直接将函数嵌入到 connect 调用中,并使用 redux 提供的通用类型来键入 connect 调用:

connect<IComponentProps, any, any, IStateStore>(
  (state, ownProps) => ({
    /* some props supplied by redux state */
  }),
  dispatch => ({
    /* some more props supplied by dispatch calls */
  })
)(Component);

但是,这也会引发错误,即嵌入式 mapStatetoPropsmapDispatchToProps 调用未定义 all Props each 因为两者只需要它们的一个子集,但一起定义了所有 Props。

如何正确键入连接调用,以便 mapStatetoPropsmapDispatchToProps 调用真正是类型安全的,并且键入检查这两种方法定义的组合值是否满足所有要求 Prop 没有一次定义所有 Prop 所需的方法之一?这在某种程度上可能通过我的方法实现吗?

最佳答案

选项 1:拆分 IComponentProps

最简单的方法可能就是为你的“state derived props”、你的“own props”和你的“dispatch props”定义单独的接口(interface),然后使用intersection type。加入他们一起参加IComponentProps

import * as React from 'react';
import { connect, Dispatch } from 'react-redux'
import { IStateStore } from '@src/reducers';


interface IComponentOwnProps {
  foo: string;
}

interface IComponentStoreProps {
  bar: string;
}

interface IComponentDispatchProps {
  fooAction: () => void;
}

type IComponentProps = IComponentOwnProps & IComponentStoreProps & IComponentDispatchProps

class IComponent extends React.Component<IComponentProps, never> {
  public render() {
    return (
      <div>
        foo: {this.props.foo}
        bar: {this.props.bar}
        <button onClick={this.props.fooAction}>Do Foo</button>
      </div>
    );
  }
}

export default connect<IComponentStoreProps, IComponentDispatchProps, IComponentOwnProps, IStateStore>(
  (state, ownProps): IComponentStoreProps => {
    return {
      bar: state.bar + ownProps.foo
    };
  },
  (dispatch: Dispatch<IStateStore>): IComponentDispatchProps => (
    {
      fooAction: () => dispatch({type:'FOO_ACTION'})
    }
  )
)(IComponent);

我们可以像这样设置连接函数的通用参数: <TStateProps, TDispatchProps, TOwnProps, State>

选项 2:让您的函数定义 Props 接口(interface)

我在野外看到的另一种选择是利用 ReturnType mapped type让你的mapX2Props函数来实际定义它们对 IComponentProps 的贡献.

type IComponentProps = IComponentOwnProps & IComponentStoreProps & IComponentDispatchProps;

interface IComponentOwnProps {
  foo: string;
}

type IComponentStoreProps = ReturnType<typeof mapStateToProps>;
type IComponentDispatchProps = ReturnType<typeof mapDispatchToProps>;

class IComponent extends React.Component<IComponentProps, never> {
  //...
}


function mapStateToProps(state: IStateStore, ownProps: IComponentOwnProps) {
  return {
    bar: state.bar + ownProps.foo,
  };
}

function mapDispatchToProps(dispatch: Dispatch<IStateStore>) {
  return {
    fooAction: () => dispatch({ type: 'FOO_ACTION' })
  };
}

export default connect<IComponentStoreProps, IComponentDispatchProps, IComponentOwnProps, IStateStore>(
  mapStateToProps,
  mapDispatchToProps
)(IComponent);

这里的最大优势是它减少了一点样板,并使它在添加新的映射 prop 时只有一个地方可以更新。

我总是避开 ReturnType ,简化因为让您的实现定义您的编程接口(interface)“契约(Contract)”(IMO)感觉倒退。更改您的 IComponentProps 变得几乎太容易了以一种你不希望的方式。

但是,由于这里的所有内容都是独立的,因此它可能是一个可以接受的用例。

关于reactjs - 如何正确输入 Redux 连接调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54155886/

相关文章:

javascript - 将指令转换为 typescript 时扩展 $scope

javascript - 与 redux react 生成的静态 SEO 友好页面,我只需要索引页面

reactjs - 未捕获的类型错误 : Cannot read property 'state or props' of undefined

javascript - TypeScript 和文件上传类型

angular - 如何以编程方式触发 optionSelected Angular Material 自动完成?

javascript - JSON 对象属性转换为 JSON 对象名称

reactjs - 如何停止开 Jest 运行测试常量文件夹

javascript - 避免重复州名

reactjs - 尝试使用 Node.js Lambda 函数在 AWS REST API 配置上通过 Axios 发布数据时出现 CORS 错误

reactjs - 在 react Spring 动画完成时更改状态,