如何从useSelector解构属性?解决读取undefined属性的类型错误
从useSelector中解构属性的可行性与问题解决
问题说明
首先明确:可以从useSelector返回的对象中解构属性,你最初的写法是完全可行的:
const { content, loading, loaded } = useSelector(state => ({ content: state.supply.content, loading: state.supply.loading, loaded: state.supply.loaded, }))
但你后续尝试直接解构content内部属性时遇到了Uncaught TypeError: Cannot read properties of undefined (reading 'items')错误,根源在于:
state.supply.content的类型是RequestContent | undefined,它可能是RequestItem、RequestCategories、RequestItems三种类型之一,甚至是undefined- 你直接用类型断言
(state.supply.content as RequestItems)强制将其转为RequestItems,但运行时如果content实际是其他类型或undefined,就会触发读取不存在属性的错误
解决方案
方案1:在Selector中做类型守卫+安全取值
在useSelector的回调里,先通过类型守卫判断content是否为RequestItems类型,再安全提取属性,同时给默认值避免后续使用出错:
const { items, category, totalCountFromServer, loading, loaded } = useSelector(state => { const { content, loading, loaded } = state.supply; // 用'in'操作符做运行时类型守卫,判断content是否是RequestItems const isRequestItems = content && 'items' in content; return { items: isRequestItems ? content.items : [], category: isRequestItems ? content.category : null, totalCountFromServer: isRequestItems ? content.totalCountFromServer : 0, loading, loaded, }; });
方案2:拆分useSelector调用(更清晰)
如果不需要一次性获取所有值,可以拆分调用,分别取基础状态和处理content属性,逻辑更直观:
// 先取基础状态 const { loading, loaded } = useSelector(state => state.supply); // 单独取content const content = useSelector(state => state.supply.content); // 安全提取content中的属性 const items = content && 'items' in content ? content.items : []; const category = content && 'items' in content ? content.category : null; const totalCountFromServer = content && 'items' in content ? content.totalCountFromServer : 0;
关键注意点
- 避免盲目使用类型断言:TypeScript的类型断言仅作用于编译阶段,不会在运行时校验类型,强行断言会埋下运行时错误隐患
- 优先用运行时类型守卫:
in操作符是处理联合类型的常用方式,能确保你读取的属性确实存在于当前值中 - 保留shallowEqual:你自定义的useSelector默认使用了
shallowEqual,能避免组件因状态浅变化导致的不必要重渲染,这个设置无需修改
内容的提问来源于stack exchange,提问作者WichyCake
相关产品推荐
相关产品推荐

