You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从类型化对象中排除特定键值?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;
});

这种方式无需修改守卫,但可读性不如拆分守卫清晰,适合简单场景临时解决问题。


架构优化建议(解决你觉得架构复杂的问题)

  1. 抽离类型与守卫函数:不要在组件内部定义TypeA、TypeB和守卫逻辑,把它们放到单独的类型文件(比如src/types/equipment.ts)中,既简化组件代码,也方便其他模块复用。
  2. 统一itemType枚举值:把字符串'typeA'、'TypeB'改成枚举类型,避免拼写错误,同时让类型检查更严格:
    enum ItemType {
      TypeA = 'typeA',
      TypeB = 'TypeB'
    }
    
  3. 补全非目标类型分支:当前代码未处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:30:54