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

ChartJS自定义squareRoot刻度遇TS类型错误,如何解决?

ChartJS自定义平方根刻度TypeScript类型错误解决方案

问题背景

按照ChartJS文档实现自定义平方根刻度,先定义了继承自Scale的SquareRootAxis类:

import { Scale, LinearScale, BubbleDataPoint, Chart, ChartTypeRegistry, ScatterDataPoint} from 'chart.js';

export default class SquareRootAxis extends Scale {
    static defaults: {} = {};
    _startValue: any;
    _valueRange: number;
    
    constructor(cfg: { id: string; type: string; ctx: CanvasRenderingContext2D; chart: Chart<keyof ChartTypeRegistry, (number | ScatterDataPoint | BubbleDataPoint)[], unknown>; }) {
      super(cfg);
      this._startValue = undefined;
      this._valueRange = 0;
    }
    
    parse(raw: any, index: number) {
      const value = LinearScale.prototype.parse.apply(this, [raw, index]);
      return isFinite(value) && value > 0 ? value : null;
    }
    
    determineDataLimits() {
      this.min = 0.5
      this.max=31
    }
    
    buildTicks() {
        const userDefinedTicks = [1, 2, 3, 5, 7, 10, 15, 20, 25, 30];
        const ticks = [];
        for (const tick of userDefinedTicks) {
            ticks.push({
                value: tick
            });
        }
        return ticks;
    }
    
    /**
     * @protected
     */
    configure() {
      const start = this.min;
      super.configure();
      this._startValue = Math.pow(start, 1/2);
      this._valueRange = Math.pow(this.max, 1/2) - Math.pow(start, 1/2);
    }
    
    getPixelForValue(value: number | undefined) {
      if (value === undefined ) {
        value = this.min;
      }
      return this.getPixelForDecimal(value === this.min ? 0 :
        (Math.pow(value, 1/2) - this._startValue) / this._valueRange);
    }
    
    getValueForPixel(pixel: number) {
      const decimal = this.getDecimalForPixel(pixel);
      return Math.pow(this._startValue + decimal * this._valueRange, 2);
    }
  }

随后在React-chartjs-2的Scatter图表中导入使用:

import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
} from 'chart.js';
import { Scatter } from 'react-chartjs-2';
import SquareRootAxis from './sqaureRootAxis';

ChartJS.register(
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
  SquareRootAxis
);

SquareRootAxis.id = 'squareRoot';

export function Chart(props: { chartData: ChartData }) {
  return <Scatter
    data={props.chartData}
    options={{
      responsive: true,
      scales: {
        x: {
          type: 'squareRoot',
        },
      },
    }}
  />;
}

设置刻度类型为squareRoot时出现TypeScript错误:

Type '"squareRoot"' is not assignable to type '"time" | "linear" | "logarithmic" | "category" | "timeseries"'.ts(2322)
index.esm.d.ts(3618, 27): The expected type comes from property 'type' which is declared here on type '_DeepPartialObject<{ type: "time"; } & Omit<CartesianScaleOptions...'

问题原因

TypeScript默认不知道你新增的自定义刻度类型,ChartJS官方类型定义仅包含内置刻度类型,因此会触发类型不匹配错误。

解决步骤

1. 扩展ChartJS类型声明

创建一个自定义类型文件(如src/chartjs-custom-scale.d.ts),通过模块扩充将自定义刻度类型加入ChartJS的类型系统:

import { ChartTypeRegistry, CartesianScaleOptions } from 'chart.js';

declare module 'chart.js' {
  // 注册自定义刻度的配置选项
  interface ChartTypeRegistry {
    squareRoot: {
      options: CartesianScaleOptions;
    };
  }

  // 扩展笛卡尔刻度类型,包含自定义刻度
  type CartesianScaleType = keyof ChartTypeRegistry;
}

2. 修正自定义刻度类的继承与静态ID

自定义刻度应继承自LinearScale而非基础Scale,这样能复用内置线性刻度的核心逻辑,同时将id设为类的静态属性:

import { LinearScale, BubbleDataPoint, Chart, ChartTypeRegistry, ScatterDataPoint} from 'chart.js';

export default class SquareRootAxis extends LinearScale {
    static id = 'squareRoot'; // 静态声明ID,无需后续赋值
    static defaults: {} = {};
    _startValue: number;
    _valueRange: number;
    
    constructor(cfg: { id: string; type: string; ctx: CanvasRenderingContext2D; chart: Chart<keyof ChartTypeRegistry, (number | ScatterDataPoint | BubbleDataPoint)[], unknown>; }) {
      super(cfg);
      this._startValue = 0;
      this._valueRange = 0;
    }
    
    // 其余方法保持不变
}

移除使用代码中的SquareRootAxis.id = 'squareRoot';,因为已经通过静态属性定义。

3. 确保TypeScript识别自定义类型文件

在tsconfig.json的include数组中添加自定义类型文件路径:

{
  "compilerOptions": {
    // 你的编译选项
  },
  "include": [
    "src/**/*",
    "src/chartjs-custom-scale.d.ts" // 替换为你的实际文件路径
  ]
}

原理说明

ChartJS的TypeScript类型基于声明文件实现,自定义扩展需要通过模块扩充告知TypeScript存在新的刻度类型,这样在配置scales.x.type = 'squareRoot'时,类型检查器会认可该值的合法性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 00:10:20