我正在尝试制作一个可重复使用的卡片组件,它需要 1 到 3 个不同类型的图表,并使用选择器在卡片内显示当前选定的图表。问题是,我不知道如何正确输入该组件的
charts
属性,该属性的类型为 charts: (LineChart | DonutChart | BarChart)[];
(联合类型数组)
单独拥有这些图表道具:
interface LineChartProps {
data: string[]; //specificLineData
}
interface BarChartProps {
data: number[]; //specificBarData
}
interface DonutChartProps {
data: {
name: string;
value: number;
}[]; //specificDonutData
}
我希望用法是这样的:
<Card
charts={[
{
key: ChartCardSwitch.CURRENT,
componentProps: {
data: ['One', 'Two', 'Three'],
},
component: LineChart,
},
{
key: ChartCardSwitch.WEEK,
componentProps: {
data: [1, 2, 3],
},
component: BarChart,
},
{
key: ChartCardSwitch.QUARTER,
componentProps: {
data: [
{ name: 'logs', value: 20 },
{ name: 'vulnerabilites', value: 30 },
],
},
component: DonutChart,
},
]}
/>
但是当我输入
Card
组件时,如下所示:
export enum ChartCardSwitch {
CURRENT = "current",
WEEK = "week",
QUARTER = "quarter",
}
interface LineChart {
key: ChartCardSwitch;
componentProps: LineChartProps;
component: FC<LineChartProps>;
}
interface DonutChart {
key: ChartCardSwitch;
componentProps: DonutChartProps;
component: FC<DonutChartProps>;
}
interface BarChart {
key: ChartCardSwitch;
componentProps: BarChartProps;
component: FC<BarChartProps>;
}
interface CardProps {
charts: (LineChart | DonutChart | BarChart)[];
}
typecheck 不会通过以下代码(没有任何强制转换),因为打字稿期望
data
属性将满足所有可能的联合图表属性 data
属性,即使从输入中应该清楚 component
和 componentProps
必须共享相同类型:
<div className={'chartContainer'}>
{activeChart && (
<activeChart.component
{...activeChart.componentProps}
// How to get rid of this any and type Card component properly
data={activeChart.componentProps.data as any}
/>
)}
</div>
还发布 codesandbox 以获得更直接的用例理解。
我会更关注数据的类型而不是属性。像这样的东西:
// first define the types of different data:
export type LineChartData = string;
export type BarChartData = number;
export type DonutChartData = {
name: string;
value: number;
};
// then create a type to use as a generic
export type ChartData = LineChartData | BarChartData | DonutChartData;
// Then create a generic type for the properties and chart
type ChartProps<T extends ChartData> = {data: T[]};
interface Chart<T extends ChartData> {
key: ChartCardSwitch;
componentProps: ChartProps<T>;
component: FC<ChartProps<T>>;
}
interface BarChart extends Chart<BarChartData>{}
interface LineChart extends Chart<LineChartData>{}
interface DonutChart extends Chart<DonutChartData> {}
这样,数据的类型将被正确推断,例如:
const bar: ChartProps<BarChartData> = {data: [1,2,3]};
const line: ChartProps<LineChartData> = {data: ['a', 'b', 'c']};
const donut: ChartProps<DonutChartData> = {data: [{name: 'a', value: 1}, {name: 'b', value: 2}, {name: 'c', value: 3}],};
// or for a chart
const lineChart: LineChart = {component: SomeLineChartComponent, componentProps: {data: ['a', 'b']}, key: ChartCardSwitch.CURRENT};