如何从类型化对象中排除特定键值?React联合类型属性访问报错解决
解决类型守卫下的属性访问报错及架构优化建议
先解决当前的weight访问报错问题
你现在的核心问题是isCurrentType仅将类型收窄到TypeA|TypeB联合类型,但TypeB不存在weight属性,导致TypeScript报错。提供两种直接解决方式:
方式1:拆分类型守卫,精准识别子类型
把单一守卫拆成两个,分别判断TypeA和TypeB,这样访问属性时类型完全明确:
// 单独判断TypeA const isTypeA = (item: any): item is TypeA => { return item?.itemType === 'typeA'; }; // 单独判断TypeB const isTypeB = (item: any): item is TypeB => { return item?.itemType === 'TypeB'; }; // 渲染时分支处理 const renderItems = items.map((el) => { if (isTypeA(el)) { return <Component id={el.id} equipment={el.equipment} weight={el.weight} />; } if (isTypeB(el)) { return <Component id={el.id} equipment={el.equipment} />; // 无需传weight,组件将使用默认/undefined } // 处理非目标类型的情况(可选,避免未处理分支导致的渲染异常) return null; });
方式2:用in操作符临时收窄类型
如果不想拆分守卫,可在访问weight前用in操作符检查属性是否存在,也能通过TypeScript的类型校验:
const renderItems = items.map((el) => { if (isCurrentType(el)) { return ( <Component id={el.id} equipment={el.equipment} weight={'weight' in el ? el.weight : undefined} /> ); } return null; });
这种方式无需修改守卫,但可读性不如拆分守卫清晰,适合简单场景临时解决问题。
架构优化建议(解决你觉得架构复杂的问题)
- 抽离类型与守卫函数:不要在组件内部定义
TypeA、TypeB和守卫逻辑,把它们放到单独的类型文件(比如src/types/equipment.ts)中,既简化组件代码,也方便其他模块复用。 - 统一
itemType枚举值:把字符串'typeA'、'TypeB'改成枚举类型,避免拼写错误,同时让类型检查更严格:enum ItemType { TypeA = 'typeA', TypeB = 'TypeB' } - 补全非目标类型分支:当前代码未处理
isCurrentType返回false的情况,建议增加返回null或默认组件的逻辑,避免出现undefined导致的渲染问题。
优化后的示例代码(类型抽离后):
// src/types/equipment.ts export enum ItemType { TypeA = 'typeA', TypeB = 'TypeB' } export type TypeA = { id: string; equipment: string; weight: string; itemType: ItemType.TypeA }; export type TypeB = { id: string; equipment: string; itemType: ItemType.TypeB }; export type EquipmentItem = TypeA | TypeB; export const isEquipmentItem = (item: any): item is EquipmentItem => { return Object.values(ItemType).includes(item?.itemType); }; export const isTypeA = (item: EquipmentItem): item is TypeA => { return item.itemType === ItemType.TypeA; }; // 组件文件 import { EquipmentItem, isEquipmentItem, isTypeA } from '../types/equipment'; const CurrentView: React.FC<Props> = () => { const items = useAppSelector((state) => state.data.itemsFromDB) as EquipmentItem[]; const renderItems = items.map((el) => { if (!isEquipmentItem(el)) return null; return ( <Component id={el.id} equipment={el.equipment} weight={isTypeA(el) ? el.weight : undefined} /> ); }); return <div>{renderItems}</div>; };
内容的提问来源于stack exchange,提问作者Richardson
相关产品推荐
相关产品推荐

