You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React TypeScript中Nivo Pie Chart类型错误求助

React TypeScript中Nivo Pie Chart类型错误解决方案

错误原因

当前代码存在两个核心问题:

  • PieChartDemo组件的data参数用any类型声明,TypeScript无法验证其是否符合Nivo ResponsivePie要求的数组类型
  • App组件中selected状态未限制取值范围,导致TypeScript无法确定data[selected]返回的是数组类型,进而触发类型不匹配错误

解决步骤

1. 定义明确的饼图数据类型

在Data.ts中添加类型定义,让TypeScript能准确识别数据结构:

// Data.ts
export interface PieDataItem {
  id: string;
  label: string;
  value: string;
}

export interface ChartData {
  tagsByNumOfFollowers: PieDataItem[];
  mostPopularPostsThisWeek: PieDataItem[];
}

const totalFollowers = 594.2
const totalMostPopularPosts = 434
const convertToPercent = (val: number, total: number) => {
  return ((val / total) * 100).toFixed(1);
}

// 为data指定明确类型
export const data: ChartData = {
  tagsByNumOfFollowers: [
    {
      id: 'General Programing',
      label: 'GP',
      value: convertToPercent(228.8, totalFollowers),
    },
    {
      id: 'JavaScript',
      label: 'JavaScript',
      value: convertToPercent(100.6, totalFollowers),
    },
    {
      id: 'Nodejs',
      label: 'Nodejs',
      value: convertToPercent(74.3, totalFollowers),
    },
    {
      id: 'React',
      label: 'React',
      value: convertToPercent(74.4, totalFollowers),
    },
    {
      id: 'Python',
      label: 'Python',
      value: convertToPercent(59.5, totalFollowers),
    },
    {
      id: 'CSS',
      label: 'CSS',
      value: convertToPercent(56.6, totalFollowers),
    },
  ],
  mostPopularPostsThisWeek: [
    {
      id: 'JavaScript',
      label: 'JavaScript',
      value: convertToPercent(134, totalMostPopularPosts),
    },
    {
      id: 'Web Dev',
      label: 'Web Dev',
      value: convertToPercent(97, totalMostPopularPosts),
    },
    {
      id: 'React',
      label: 'React',
      value: convertToPercent(60, totalMostPopularPosts),
    },
    {
      id: 'Dev Blogs',
      label: 'Dev Blogs',
      value: convertToPercent(46, totalMostPopularPosts),
    },
    {
      id: 'Python',
      label: 'Python',
      value: convertToPercent(60, totalMostPopularPosts),
    },
    {
      id: 'CSS',
      label: 'CSS',
      value: convertToPercent(37, totalMostPopularPosts),
    },
  ],
}

2. 修正PieChartDemo组件的Props类型

替换any类型为明确的数组类型,确保传入的data符合Nivo组件要求:

// PieChartDemo.tsx
import { ResponsivePie } from '@nivo/pie'
import { PieDataItem } from './Data'

// 明确props的data类型为PieDataItem数组
export const PieChartDemo = ({ data }: { data: PieDataItem[] }) => (
  <div style={{ width: '600px', height: '500px' }}>
    <ResponsivePie
      data={data}
      margin={{ top: 40, right: 150, bottom: 80, left: 150 }}
      innerRadius={0.5}
      padAngle={0.7}
      cornerRadius={3}
      activeOuterRadiusOffset={8}
      borderWidth={1}
      borderColor={{ from: 'color', modifiers: [['darker', 0.2]] }}
      arcLinkLabelsSkipAngle={10}
      arcLinkLabelsTextColor='#333333'
      arcLinkLabelsThickness={2}
      arcLinkLabelsColor={{ from: 'color' }}
      arcLabelsSkipAngle={10}
      arcLabelsTextColor={{ from: 'color', modifiers: [['darker', 2]] }}
      valueFormat={(value) => `${Number(value)} %`}
      legends={[
        {
          anchor: 'bottom',
          direction: 'row',
          justify: false,
          translateX: 0,
          translateY: 56,
          itemsSpacing: 0,
          itemWidth: 90,
          itemHeight: 18,
          itemTextColor: '#999',
          itemDirection: 'left-to-right',
          itemOpacity: 1,
          symbolSize: 15,
          symbolShape: 'circle',
          effects: [
            {
              on: 'hover',
              style: {
                itemTextColor: '#000',
              },
            },
          ],
        },
      ]}
    />
  </div>
)

3. 限制App组件中selected状态的取值范围

通过keyof ChartData确保selected只能取ChartData中存在的键,让TypeScript能正确推断data[selected]的类型:

// App.tsx
import { useState } from "react";
import styles from '../styles/Home.module.css'
import { data, ChartData } from "./component/Data";
import { PieChartDemo } from "./component/PieChartDemo";

// 定义selected的类型为ChartData的键
type SelectedKey = keyof ChartData;

const App = () => {
  const [selected, setSelected] = useState<SelectedKey>('tagsByNumOfFollowers')

  return (
    <div>
     <div className={styles.container}>
      <main className={styles.main}>
        <select
          onChange={(e) => {
            setSelected(e.target.value as SelectedKey)
          }}
          value={selected}
        >
          <option value='tagsByNumOfFollowers'>Tags followed</option>
          <option value='mostPopularPostsThisWeek'>
            Most popular posts this week
          </option>
        </select>
        <PieChartDemo data={data[selected]} />
      </main>
    </div>
    </div>
  );
}

export default App;

额外说明

  • 添加类型定义后,TypeScript能在编译阶段检测数据结构错误,避免运行时问题
  • 限制selected取值范围可以防止传入不存在的键值,提升代码健壮性

内容的提问来源于stack exchange,提问作者Kapil Panchal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:17:09