如何输入组件的数组 prop(联合类型数组)以获得正确的类型检查

问题描述 投票:0回答:1

我正在尝试制作一个可重复使用的卡片组件,它需要 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 以获得更直接的用例理解。

reactjs typescript
1个回答
0
投票

我会更关注数据的类型而不是属性。像这样的东西:

// 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};
© www.soinside.com 2019 - 2024. All rights reserved.