Chart.js升级3.8.0后设置options.scales.x.time报TS2339错误
问题描述
将项目中chart.js从2.9.4版本升级至3.8.0版本时,ChartConfiguration类型下options.scales.x的time属性出现TypeScript类型缺失报错,给options.scales.x.time.unit赋值时触发如下错误:
error TS2339: Property 'time' does not exist on type '_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number; suggestedMax?: number; grace?: string | number; ticks: { format: NumberFormatOptions; precision: number; stepSize: number; count: number; }; }> | _DeepPartialObject<...> | _DeepPartialObject<...> | _DeepPa...'.
最初怀疑问题和ng2-charts库有关,但移除该依赖后问题仍可复现。
最小复现代码
import { Component, OnInit } from '@angular/core'; import { ChartConfiguration } from 'chart.js'; @Component({ selector: 'daily-chart', templateUrl: './daily-chart.component.html', styleUrls: ['./daily-chart.component.scss'] }) export class DailyChartComponent implements OnInit { chartConfig: ChartConfiguration<'line'> = { data: { datasets: [] }, type: 'line', options: { scales: { x: { type: 'time', time: { unit: 'day', }, } } } } constructor() { } ngOnInit() { this.chartConfig.options.scales.x.time.unit = 'week'; // 报错行 } }
项目依赖版本
chart.js: 3.8.0ng2-charts: 3.0.11angular: 13.3.5tslib: 2.4.0typescript: 4.6.4chartjs-adapter-moment: 1.0.0chartjs-plugin-annotation: 1.4.0chartjs-plugin-datalabels: 2.0.0
问题原因
这个问题和ng2-charts无关,是Chart.js 3.x的类型设计+TypeScript类型收窄规则共同导致的:
- Chart.js 3.x对不同类型的坐标轴做了严格的类型区分:线性轴、类别轴、时间轴等各自有独立的配置类型,只有时间轴(
type: 'time')的类型定义上才存在time配置属性。 - 初始化
chartConfig时,TypeScript会根据传入的对象字面量做上下文类型推断,识别到x轴设置了type: 'time',所以初始化阶段写time配置不会报错。 - 但在
ngOnInit中动态访问this.chartConfig.options.scales.x时,TypeScript是基于ChartConfiguration<'line'>的公开声明类型做校验,这个类型里scales.x是所有支持的坐标轴类型的联合类型,不会保留初始化时传入的字面量type: 'time'的信息。联合类型中除了时间轴之外的其他坐标轴类型都没有time属性,因此访问时触发类型报错。 - Chart.js 2.x的类型定义比较宽松,没有做这种按坐标轴类型的严格属性校验,所以升级前不会出现该问题。
修复方案
任选以下一种方案即可解决:
方案1:访问时做显式类型断言(改动最小)
导入Chart.js内置的TimeScaleOptions类型,在访问x轴配置时做类型断言,明确告知TypeScript该轴为时间轴:
import { ChartConfiguration, TimeScaleOptions } from 'chart.js'; // ...其他代码不变 ngOnInit() { (this.chartConfig.options.scales.x as TimeScaleOptions).time.unit = 'week'; }
方案2:初始化时明确x轴的类型
在配置x轴时直接断言为TimeScaleOptions类型,让TypeScript从初始化阶段就确定x轴的类型:
chartConfig: ChartConfiguration<'line'> = { // data、type配置不变 options: { scales: { x: { type: 'time', time: { unit: 'day', }, } as TimeScaleOptions } } }
修改后后续访问this.chartConfig.options.scales.x.time不会再报类型错误。
方案3:抽离坐标轴配置为独立变量
把时间轴的配置抽成带明确类型的独立变量,初始化时引用这个变量,后续修改配置直接操作独立变量即可,不需要从chartConfig深层取值:
private xTimeScale: TimeScaleOptions = { type: 'time', time: { unit: 'day' } }; chartConfig: ChartConfiguration<'line'> = { data: { datasets: [] }, type: 'line', options: { scales: { x: this.xTimeScale } } } ngOnInit() { this.xTimeScale.time.unit = 'week'; // 无类型报错 }
内容的提问来源于stack exchange,提问作者fieldhof
相关产品推荐
相关产品推荐

