【问题标题】:Inferring mapped props when using TypeScript and React-Redux使用 TypeScript 和 React-Redux 时推断映射的道具
【发布时间】:2020-02-25 15:10:37
【问题描述】:

我找到了一种在使用来自react-reduxmapStateToProps 时获得类型安全的方法:作为documented,您可以定义一个接口并使用您的接口参数化React.Component<T>

但是,当我定义mapStateToProps 时,我已经定义了一个函数,可以推断结果对象的属性类型。例如,

function mapStateToProps(state: MyState) {
    return {
        counter: state.counter
    };
}

这里,counter 可以推断为与state.counter 相同的类型。但我仍然必须有如下样板代码:

interface AppProps {
    counter: number;
}


class App extends React.Component<AppProps> { ... }

export default connect(mapStateToProps)(App);

所以问题是,有没有什么方法可以构造代码,这样我就可以避免两次编写counter 的类型?或者为了避免参数化React.Component 的类型——即使我可以从mapStateToProps 函数的显式提示结果类型中推断出组件的属性,这将是更可取的。我想知道上面的重复是否确实是使用 React-Redux 编写类型化组件的正常方式。

【问题讨论】:

    标签: javascript reactjs typescript redux react-redux


    【解决方案1】:

    我不这么认为。您可以使用 Redux 挂钩使您的设置更简洁:https://react-redux.js.org/next/api/hooks

        // Your function component . You don't need to connect it
        const App: React.FC = () => {
          const counter = useSelector<number>((state: MyState) => state.counter);
          const dispatch = useDispatch(); // for dispatching actions
        };
    

    编辑:如果您只使用相同的MyState 类型,则可以。但我不认为你会想要那个。

    【讨论】:

      【解决方案2】:

      我会分别输入映射的调度道具和组件道具,然后将映射状态的推断类型组合到道具函数中。请参阅下面的快速示例。可能有一个更优雅的解决方案,但希望它能让您走上正轨。

      import * as React from "react";
      import { Action } from "redux";
      import { connect } from "react-redux";
      
      // Lives in some lib file
      type AppState = {
        counter: number;
      };
      
      type MappedState = {
        computedValue: number;
      };
      type MappedDispatch = {
        doSomethingCool: () => Action;
      };
      type ComponentProps = {
        someProp: string;
      };
      
      const mapStateToProps = (state: AppState) => ({
        computedValue: state.counter
      });
      
      const mapDispatchToProps: MappedDispatch = {
        doSomethingCool: () => {
          return {
            type: "DO_SOMETHING_COOL"
          };
        }
      };
      
      type Props = ReturnType<typeof mapStateToProps> &
        MappedDispatch &
        ComponentProps;
      
      class DumbComponent extends React.Component<Props> {
        render() {
          return (
            <div>
              <h1>{this.props.someProp}</h1>
              <div>{this.props.computedValue}</div>
              <button onClick={() => this.props.doSomethingCool()}>Click me</button>
            </div>
          );
        }
      }
      
      const SmartComponent = connect(
        mapStateToProps,
        mapDispatchToProps
      )(DumbComponent);
      
      export default SmartComponent;
      

      【讨论】:

        【解决方案3】:

        是的。有一种巧妙的技术可以根据mapStatemapDispatch 推断connect 将传递给您的组件的组合道具的类型。

        @types/react-redux@7.1.2 中提供了一个新的 ConnectedProps&lt;T&gt; 类型。你可以这样使用它:

        function mapStateToProps(state: MyState) {
            return {
                counter: state.counter
            };
        }
        
        const mapDispatch = {increment};
        
        // Do the first half of the `connect()` call separately, 
        // before declaring the component
        const connector = connect(mapState, mapDispatch);
        
        // Extract "the type of the props passed down by connect"
        type PropsFromRedux = ConnectedProps<typeof connector>
        // should be: {counter: number, increment: () => {type: "INCREMENT"}}, etc
        
        // define combined props
        type MyComponentProps = PropsFromRedux & PropsFromParent;
        
        // Declare the component with the right props type
        class MyComponent extends React.Component<MyComponentProps> {}
        
        // Finish the connect call
        export default connector(MyComponent)
        

        请注意,如果mapDispatch 是一个对象,这会正确推断出包含在typeof mapDispatch 中的thunk 动作创建者的类型,而typeof mapDispatch 则不会。

        我们将尽快将此作为推荐方法添加到官方 React-Redux 文档中。

        更多细节:

        【讨论】:

        • 这太棒了!这与切片的结合确实使 redux 更容易使用
        猜你喜欢
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 2019-06-21
        • 2021-08-31
        • 2016-12-03
        • 2020-05-18
        • 2018-12-04
        • 2020-11-15
        相关资源
        最近更新 更多