React TypeScript中Nivo Pie Chart类型错误求助
React TypeScript中Nivo Pie Chart类型错误解决方案
错误原因
当前代码存在两个核心问题:
PieChartDemo组件的data参数用any类型声明,TypeScript无法验证其是否符合NivoResponsivePie要求的数组类型- 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
相关产品推荐
相关产品推荐

