TypeScript中如何定义接收不同Props类型React.FC的组件Prop类型
你遇到的类型报错本质是TypeScript函数参数的逆变特性导致的:React.FC<Props>的泛型参数Props属于函数入参类型,是逆变的。
你定义的image: React.FC<ProductImageProps | OrderImageProps>表示这个组件需要兼容两种Props的任意一种作为入参,但你传入的ProductImage只能接受ProductImageProps、OrderImage只能接受OrderImageProps,都不满足“兼容两种入参”的要求,所以赋值失败,和XOR类型没有关系。
如果你一定要沿用原实现,可以修改CustomDataTableProps的image类型为组件的联合类型,再对props做类型断言绕开校验:
interface CustomDataTableProps { // 其他原有属性保留 image: React.FC<ProductImageProps> | React.FC<OrderImageProps> list: boolean } // 组件内创建元素时加类型断言 image: React.createElement(props.image, (props.list ? { orders: cartItems } : { src: product.src } ) as Parameters<typeof props.image>[0])
该方案的缺陷非常明显:后续新增其他图像组件时,需要不断修改CustomDataTableProps的image联合类型,同时还要维护组件内的props条件判断逻辑,扩展性、可维护性都很差。
针对你后续还要新增更多条件渲染组件的场景,Render Prop是性价比最高的方案,完全不需要修改表格组件本身的逻辑,类型天然安全:
1. 修改表格组件Props定义
把固定的image组件属性改为渲染函数,接受当前行数据和list状态作为入参,返回渲染节点:
interface CustomDataTableProps { // 其他原有属性全部保留 renderImage: (item: ICartItem, isList: boolean) => React.ReactNode list: boolean }
2. 表格内直接调用渲染函数
不需要再做条件判断、创建元素的逻辑,直接调用传入的render函数即可:
const sampleData = sampleProducts.map((product: ICartItem) => { return { image: props.renderImage(product, props.list), // 其他原有数据保留 } })
3. 调用表格组件时自定义渲染逻辑
需要用什么组件直接在调用侧定义即可,完全不需要改动表格组件代码:
// 渲染商品图场景 <CustomDataTable // 其他属性省略 list={false} renderImage={(product) => <ProductImage src={product.src} />} /> // 渲染订单列表场景 const cartItems = useSelector((state: RootState) => state.cart.cartItems) <CustomDataTable // 其他属性省略 list={true} renderImage={() => <OrderImage orders={cartItems} />} />
后续新增任何图像组件,都只需要在调用侧写对应的渲染逻辑即可,表格组件不需要做任何调整,适配性极强。
内容的提问来源于stack exchange,提问作者Neminda Prabhashwara

