React TypeScript中ECharts的series属性类型不兼容问题排查
问题背景
在React项目中参考文档实现Apache ECharts,Codesandbox示例运行正常,但本地项目触发TypeScript类型错误。
错误信息
TS2322: Type '{ legend: {}; tooltip: { trigger: string; showContent: boolean; }; xAxis: { type: string; }; yAxis: { gridIndex: number; }; series: { data: number[]; type: string; smooth: boolean; }[]; }' is not assignable to type 'EChartsOption'.
Type '{ legend: {}; tooltip: { trigger: string; showContent: boolean; }; xAxis: { type: string; }; yAxis: { gridIndex: number; }; series: { data: number[]; type: string; smooth: boolean; }[]; }' is not assignable to type '{ grid?: Arrayable; series?: Arrayable<LineSeriesOption$1>; title?: Arrayable; }'.
Types of property 'series' are incompatible.
Type '{ data: number[]; type: string; smooth: boolean; }[]' is not assignable to type 'Arrayable<LineSeriesOption$1>'.
Type '{ data: number[]; type: string; smooth: boolean; }[]' is not assignable to type 'LineSeriesOption$1[]'.
Type '{ data: number[]; type: string; smooth: boolean; }' is not assignable to type 'LineSeriesOption$1'.
Type '{ data: number[]; type: string; smooth: boolean; }' is not assignable to type 'LineSeriesOption'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type '"line"'.
ReactECharts.tsx(31, 5): The expected type comes from property 'option' which is declared here on type 'IntrinsicAttributes & ReactEChartsProps'
组件代码
import type { LineSeriesOption } from "echarts/charts"; import { LineChart } from "echarts/charts"; import type { GridComponentOption, TitleComponentOption } from "echarts/components"; import { DataZoomComponent, GridComponent, LegendComponent, TitleComponent, ToolboxComponent, TooltipComponent } from "echarts/components"; import type { ComposeOption, ECharts, SetOptionOpts } from "echarts/core"; import { getInstanceByDom, init, use } from "echarts/core"; import { CanvasRenderer } from "echarts/renderers"; import { CSSProperties, useEffect, useRef } from "react"; use([ LegendComponent, LineChart, GridComponent, TooltipComponent, TitleComponent, ToolboxComponent, DataZoomComponent, CanvasRenderer ]); export type EChartsOption = ComposeOption< LineSeriesOption | TitleComponentOption | GridComponentOption >; export interface ReactEChartsProps { option: EChartsOption; style?: CSSProperties; settings?: SetOptionOpts; } export function ReactECharts({ option, style, settings }: ReactEChartsProps): JSX.Element { const chartRef = useRef<HTMLDivElement>(null); useEffect(() => { let chart: ECharts | undefined; if (chartRef.current !== null) { chart = init(chartRef.current); } function resizeChart() { chart?.resize(); } window.addEventListener("resize", resizeChart); return () => { chart?.dispose(); window.removeEventListener("resize", resizeChart); }; }, []); useEffect(() => { if (chartRef.current !== null) { const chart = getInstanceByDom(chartRef.current); chart?.setOption(option, settings); } }, [option, settings]); return ( <div ref={chartRef} style={{ width: "100%", height: "300px", ...style }} /> ); }
传递的Option配置
const option = { legend: {}, tooltip: { trigger: "axis", showContent: true, }, xAxis: { type: "category" }, yAxis: { gridIndex: 0 }, series: [ { data: [45000, 45000, 45000, 45000, 45000, 75000, 45000, 45000, 45000, 45000, 55000, 45000], type: "line", smooth: true, }, ], };
tsconfig.json配置
{ "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": false, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "ts-node": { "compilerOptions": { "module": "commonjs", } }, "include": ["src"] }
解决方案
1. 补充EChartsOption的类型定义
当前EChartsOption只包含了LineSeries、Title、Grid的配置类型,但你的option里用到了Legend、Tooltip、XAxis、YAxis,需要把这些组件的类型补充到ComposeOption的联合类型中:
修改组件中的类型导入和EChartsOption定义:
import type { GridComponentOption, TitleComponentOption, LegendComponentOption, TooltipComponentOption, XAxisComponentOption, YAxisComponentOption } from "echarts/components"; // 更新EChartsOption类型 export type EChartsOption = ComposeOption< LineSeriesOption | TitleComponentOption | GridComponentOption | LegendComponentOption | TooltipComponentOption | XAxisComponentOption | YAxisComponentOption >;
2. 给Option配置指定类型
TypeScript会把type: "line"推断为string类型,但LineSeriesOption要求type是字面量类型"line",给option指定EChartsOption类型即可解决这个问题:
const option: EChartsOption = { legend: {}, tooltip: { trigger: "axis", showContent: true, }, xAxis: { type: "category" }, yAxis: { gridIndex: 0 }, series: [ { data: [45000, 45000, 45000, 45000, 45000, 75000, 45000, 45000, 45000, 45000, 55000, 45000], type: "line", smooth: true, }, ], };
完成以上两步后,TypeScript的类型错误即可消除。
内容的提问来源于stack exchange,提问作者Leff

