我有两个功能组件,它们有两种不同的道具类型。
export interface OrderImageProps {
orders: ICartItem[]
}
const OrderImage: React.FC<OrderImageProps> = (props: OrderImageProps) => {
return (
<div>
// show some list
</div>
);
};和
export interface ProductImageProps {
src: string
}
const ProductImage: React.FC<ProductImageProps> = (props: ProductImageProps) => {
return (
<Image className='img-fluid admin-product-image' src={props.src}/>
);
};这两个组件是表的实体,但有条件地呈现。因此,我需要将这两个组件传递给表组件。
interface CustomDataTableProps {
nameTag: string
itemTag: string
priceTag: string
categoryTag: string
dateTag: string
actionsTag: string
image: React.FC<ProductImageProps | OrderImageProps>
list: boolean
}
const CustomDataTable: React.FC<CustomDataTableProps> = (props: CustomDataTableProps) => {
const cartItems: ICartItem[] = useSelector((state: RootState): ICartItem[] => (state.cart.cartItems));
const sampleData = sampleProducts.map((product: ICartItem) => {
return {
image: React.createElement(props.image, props.list ?
{
orders: cartItems
} :
{
src: product.src
}),
// more data are in here
};
}但是当将道具传递给CustomDataTable时,它会显示FC<ProductImageProps> is not assignable to type FC<ProductImageProps | OrderImageProps>。
我理解这个错误,显然它们是不兼容的类型。
据我理解,这些道具可能需要XOR类型的React.FC<>行为。
这可以很容易地通过在CustomDataTable上提供一个CustomDataTable来实现。还有其他一些表实体,它们具有类似于这种有条件呈现的组件。
我的第一种方法可以实现吗?还是使用渲染道具更好?
发布于 2021-06-29 07:29:38
React.FC本质上是一个带有额外步骤的函数类型。并在React.FC<P>中键入参数React.FC<P>位于负/反变位置。
当您尝试将image螺旋桨传递给CustomDataTable时,它会检查函数的兼容性,而当涉及到参数时,它会向相反的方向检查它们。当您将参数传递给React.FC<ProductImageProps>类型时,它不会检查ProductImageProps是否可分配给ProductImageProps | OrderImageProps,而是检查ProductImageProps | OrderImageProps是否可分配给ProductImageProps。显然不是。
将image道具类型更改为React.FC<ProductImageProps> | React.FC<OrderImageProps>将消除以前的... is not assignable ...错误。但是您将在React.createElement呼叫站点上得到另一个错误。
现在,您的新props.image具有React.FC<ProductImageProps> | React.FC<OrderImageProps>类型。但是这种类型只接受ProductImageProps & OrderImageProps类型的参数。也就是说,拥有来自两种道具类型的所有必需字段。
type PropsA = { a: string }
type PropsB = { b: string }
type A = (propsA: PropsA) => void
type B = (propsB: PropsB) => void
type AB = A | B
function fnFromAB(ab: AB): void { // ab has type (args: PropsA & PropsB) => void
ab({ a: 'string' }) // error
ab({ b: 'string' }) // error
ab({ a: 'string ', b: 'string' }) // no error
}解决方案是使image组件的类型依赖于它的道具类型。由于道具的类型取决于list标志,所以您可以将代码重写为:
type CustomDataTableProps = {
nameTag: string
itemTag: string
priceTag: string
categoryTag: string
dateTag: string
actionsTag: string
} & ({
image: React.FC<OrderImageProps>
list: true
} | {
image: React.FC<ProductImageProps>
list: false
})
const CustomDataTable: React.FC<CustomDataTableProps> = (props: CustomDataTableProps) => {
const cartItems: ICartItem[] = useSelector((state: RootState): ICartItem[] => (state.cart.cartItems));
const sampleData = sampleProducts.map((product: ICartItem) => {
const image = props.list
? React.createElement(props.image, { orders: cartItems })
: React.createElement(props.image, { src: product.src })
return {
image,
// more data are in here
};
}不幸的是,您将不得不重复React.createElement调用,因为props.image在三元操作符的每个分支中都有不同的类型。
当然,您可以使用类型断言来偷工减料。但为了类型安全的代价。像往常一样。
https://stackoverflow.com/questions/68172716
复制相似问题