如何在TypeScript+Redux中通过Props访问调度方法并满足TS类型要求?
你遇到的问题是刚接触Redux+TypeStack时的典型误区——把组件的Props类型和Redux的状态类型搞混了。核心矛盾在于:你的组件接收的Props是从Redux映射来的状态属性加上绑定好的dispatch动作方法,但你直接把StoreState(仅描述Redux数据结构)作为组件Props类型,TypeScript自然会因为StoreState里没有getSummoners方法而报错。
不用在状态类型里混入动作方法,我们可以通过拆分并组合Props类型来完美解决,下面是具体步骤:
1. 拆分并定义组件的完整Props类型
把组件需要的Props分成两部分,再合并成完整类型:
import { Summoner } from "../../models/Summoner"; import { getSummoners } from './storeSlice'; // 从Redux状态映射来的属性 interface StateProps { summoners: Summoner[]; } // 从dispatch映射来的动作方法,用typeof自动推导类型 interface DispatchProps { getSummoners: typeof getSummoners; } // 组件的完整Props = 状态属性 + 动作方法 type StoreComponentProps = StateProps & DispatchProps;
2. 修正组件的Props参数类型
把组件的参数类型改成上面定义的StoreComponentProps,这样TypeScript就认可props.getSummoners的存在了:
import React, { useEffect } from 'react'; const Store = (props: StoreComponentProps) => { // 现在可以正常调用动作方法了 useEffect(() => { props.getSummoners(); }, []); console.log("store props", props); return ( <h1>Hello!</h1> ); }
3. 修正mapStateToProps的根状态类型
mapStateToProps的参数是Redux的全局根状态,不是单个slice的状态。假设你的根状态结构是{ store: StoreState }(对应你的slice名称),需要明确这个类型:
// 定义Redux全局根状态类型(如果还没在全局文件定义的话) interface RootState { store: StoreState; } const mapStateToProps = (state: RootState): StateProps => { console.log("Store state", state); return { summoners: state.store.summoners }; };
4. 简化mapDispatchToProps(推荐)
你不需要手动写mapDispatchToProps,直接把动作对象传给connect,Redux会自动绑定dispatch,同时TypeScript会自动推导类型:
// 删掉原来的mapDispatchToProps,直接传动作对象即可 export default connect(mapStateToProps, { getSummoners })(Store);
如果一定要手动实现mapDispatchToProps,可以用bindActionCreators保证类型安全:
import { bindActionCreators, Dispatch } from 'redux'; const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => { return bindActionCreators({ getSummoners }, dispatch); };
核心思路总结
Redux的connect本质是把Redux的状态和动作,转换成组件能直接用的Props。所以组件的Props类型必然是状态属性和动作方法的组合,和Redux的状态类型是完全不同的概念。把两者分开定义,既符合TypeScript的类型设计原则,也让代码结构更清晰。
内容的提问来源于stack exchange,提问作者ThePerplexedOne

