React可复用组件TypeScript联合类型校验报错解决方案
TS联合类型组件类型校验问题修复
你在开发可复用React卡片组件时,组件入参接收Car、Truck两种类型之一的API数据,通过isCar标记判断类型后访问对应id字段传入回调,JS环境下运行正常,但TS抛出类型错误,提示Truck类型不存在carId属性。
问题原因
TS的自动类型收窄无法将独立传入的isCar布尔值和data的实际类型关联,在TS的判定里data始终是Car | Truck联合类型,访问data.carId时,TS会校验联合类型的所有成员是否都存在该属性,发现Truck类型没有该字段就会抛出错误。
可行解决方案(均不破坏组件复用性)
方案1:使用可辨识联合重构类型(最推荐,类型安全度最高)
废弃独立传入的isCar参数,给Car和Truck类型添加统一的字面量标识字段,TS可以通过这个标识自动完成类型收窄,还能从根源避免isCar和data实际类型不匹配的传参bug。// 类型定义添加可辨识标识 type Car = { type: 'car'; carId: number; // 其余Car类型属性 } type Truck = { type: 'truck'; truckId: number; // 其余Truck类型属性 } type Props = { data: Car | Truck; onToggleDataSave: (id: number, isHome: boolean) => void; }; const Card = ({ data, onToggleDataSave }: Props) => { const handleToggleCardSave = (e: SyntheticEvent) => { e.preventDefault(); // TS会根据data.type自动收窄类型,不会报属性不存在错误 data.type === 'car' ? onToggleDataSave(data.carId, true) : onToggleDataSave(data.truckId, false); }; return <h1>Some markup</h1>; };方案2:保留现有入参结构,使用类型断言收窄
如果暂时不想调整现有类型和入参结构,可以通过类型断言手动告诉TS当前分支下的data类型,需要自行保证isCar和data实际类型一致。type Props = { data: Car | Truck; onToggleDataSave: (id: number, isHome: boolean) => void; isCar: boolean; }; const Card = ({ data, onToggleDataSave, isCar }: Props) => { const handleToggleCardSave = (e: SyntheticEvent) => { e.preventDefault(); isCar ? onToggleDataSave((data as Car).carId, isCar) : onToggleDataSave((data as Truck).truckId, isCar); }; return <h1>Some markup</h1>; };方案3:统一同含义字段命名,消除类型差异
如果业务场景允许,可以在接口数据格式化阶段,将Car的carId、Truck的truckId统一映射为同名字段比如id,组件内部不需要做类型判断,代码最简洁。// 统一id字段名 type Car = { id: number; // 其余Car类型属性 } type Truck = { id: number; // 其余Truck类型属性 } type Props = { data: Car | Truck; onToggleDataSave: (id: number, isHome: boolean) => void; isCar: boolean; }; const Card = ({ data, onToggleDataSave, isCar }: Props) => { const handleToggleCardSave = (e: SyntheticEvent) => { e.preventDefault(); // 直接访问统一id,无需类型判断 onToggleDataSave(data.id, isCar); }; return <h1>Some markup</h1>; };
优先推荐方案1,完全利用TS的类型检查能力,不会引入额外的人为维护成本,也不会出现类型和传参不匹配的隐性bug。
内容的提问来源于stack exchange,提问作者SrdjaNo1
相关产品推荐
相关产品推荐

