使用 TypeScript 和 React-Redux 时推断映射的 props

IT技术 javascript reactjs typescript redux react-redux
2021-04-28 16:27:09

我找到了一种在使用mapStateToPropsfrom时获得类型安全的方法react-redux:如文档所述,您可以定义一个接口并React.Component<T>使用您的接口进行参数化

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

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

在这里,counter可以推断propstate.counter. 但我仍然必须有如下样板代码:

interface AppProps {
    counter: number;
}


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

export default connect(mapStateToProps)(App);

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

3个回答

是的。还有用于推断组合props的种类整齐的技术connect将通过基于你的组件mapStatemapDispatch

中有一种新ConnectedProps<T>类型可用@types/react-redux@7.1.2你可以这样使用它:

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如果它是一个对象,这会正确推断包含在其中的thunk 动作创建者的类型,而typeof mapDispatch不是。

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

更多细节:

我不这么认为。您可以使用 Redux hooks 使您的设置更加简洁: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类型,则可以。但我不认为你会想要那样。

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

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;