[英]Inferring mapped props when using TypeScript and React-Redux
我找到了一种在使用mapStateToProps
中的react-redux
时获得类型安全的方法:如文档所述,您可以定义一个接口并使用您的接口参数化React.Component<T>
。
但是,当我定义mapStateToProps
时,我已经定义了一个 function ,其中可以推断出结果 object 的属性类型。 例如,
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
function 的明确提示的结果类型推断出组件的 props,这将是更可取的。 我想知道上面的重复是否确实是使用 React-Redux 编写类型化组件的正常方式。
是的。 有一种巧妙的技术可以根据mapState
和mapDispatch
推断connect
的组合道具的类型。
@types/react-redux@7.1.2
中有一个新的ConnectedProps<T>
类型。 你可以像这样使用它:
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)
请注意,如果它是 object,则这会正确推断mapDispatch
中包含的 thunk 动作创建者的类型,而typeof mapDispatch
则不会。
我们将很快将此添加到官方 React-Redux 文档中,作为推荐方法。
更多细节:
我不这么认为。 您可以使用 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
类型,则可以。 但我不认为你会想要那个。
我将分别键入映射的调度道具和组件道具,然后将映射的 state 的推断类型组合到道具 function。 请参阅下面的快速示例。 可能有一个更优雅的解决方案,但希望它能让你走上正确的轨道。
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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.