Using ApexCharts with TypeScript
TypeScript support
ApexCharts ships TypeScript definitions as part of its npm package. The main type you need is ApexOptions, which covers the entire configuration object you pass to new ApexCharts(el, options). For more granular work, sub-types like ApexChart, ApexXAxis, and ApexAxisChartSeries let you type individual sections of the config independently.
No separate @types/ package is needed. The definitions are bundled with apexcharts.
Importing types
All types are exported from the apexcharts package. Use import type so they are erased at compile time and add no runtime cost:
import type {
ApexOptions,
ApexAxisChartSeries,
ApexNonAxisChartSeries,
ApexChart,
ApexXAxis,
ApexYAxis,
ApexTooltip,
ApexLegend,
ApexDataLabels,
ApexStroke,
ApexFill,
ApexMarkers,
ApexTheme,
ApexPlotOptions,
ApexAnnotations,
ApexGrid,
ApexResponsive,
} from 'apexcharts'
You rarely need all of these at once. Import only what your code references.
Typing the full options object with ApexOptions
The simplest approach is to annotate the entire config object as ApexOptions. TypeScript then checks every property you set and catches typos or incorrect values immediately:
import ApexCharts from 'apexcharts'
import type { ApexOptions } from 'apexcharts'
const options: ApexOptions = {
chart: {
type: 'line',
height: 350,
},
series: [
{ name: 'Sales', data: [30, 40, 35, 50, 49] },
],
xaxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
},
}
const el = document.querySelector('#chart')!
const chart = new ApexCharts(el, options)
chart.render()
The ! non-null assertion on querySelector is covered in the strict mode section below.
Typing sub-sections
When you build a chart config incrementally (for example in a component where each section is a separate variable or prop), use the sub-types to get per-section checking:
import type {
ApexChart,
ApexXAxis,
ApexAxisChartSeries,
ApexOptions,
} from 'apexcharts'
const chartConfig: ApexChart = {
type: 'bar',
height: 350,
toolbar: { show: false },
}
const series: ApexAxisChartSeries = [
{ name: 'Revenue', data: [44, 55, 41, 67, 22] },
{ name: 'Expenses', data: [13, 23, 20, 8, 13] },
]
const xaxis: ApexXAxis = {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
}
// Compose into the final options object
const options: ApexOptions = {
chart: chartConfig,
series,
xaxis,
}
Splitting options this way is useful when sections come from different sources (API calls, component inputs, derived state) and you want type safety at each boundary before they are merged.
Series types: axis vs non-axis
ApexCharts has two distinct series shapes depending on the chart type.
ApexAxisChartSeries
Used with charts that have an x-axis and y-axis: line, area, bar, scatter, bubble, heatmap, candlestick, boxPlot, rangeBar, rangeArea, treemap.
Each item in the array is an object with a name and a data array:
import type { ApexAxisChartSeries } from 'apexcharts'
// Simple numeric data
const series: ApexAxisChartSeries = [
{ name: 'Visitors', data: [100, 200, 150, 300] },
]
// Object data with explicit x and y values
const timeSeriesData: ApexAxisChartSeries = [
{
name: 'Downloads',
data: [
{ x: 'Week 1', y: 120 },
{ x: 'Week 2', y: 200 },
{ x: 'Week 3', y: 175 },
],
},
]
ApexNonAxisChartSeries
Used with charts that have no axes: pie, donut, radialBar, polarArea.
This is a flat array of numbers, one per segment:
import type { ApexNonAxisChartSeries } from 'apexcharts'
const series: ApexNonAxisChartSeries = [44, 55, 13, 33]
const options: ApexOptions = {
chart: { type: 'donut' },
series,
labels: ['Team A', 'Team B', 'Team C', 'Team D'],
}
Using the wrong shape for a chart type will not produce a TypeScript error at the series declaration site (both shapes are valid arrays), but assigning via ApexOptions and the correct sub-type annotation makes the intent explicit and readable.
The chart.type widening gotcha
TypeScript infers string literals as string unless you tell it otherwise. This causes a problem when you store the chart type in a variable and then use it inside ApexOptions:
import type { ApexOptions } from 'apexcharts'
// Problem: TypeScript infers `type` as `string`, not as the literal 'bar'
const type = 'bar'
const options: ApexOptions = {
chart: { type }, // Error: Type 'string' is not assignable to type ChartType
}
There are two ways to fix this:
// Fix 1: use `as const` to preserve the literal type
const type = 'bar' as const
const options: ApexOptions = {
chart: { type }, // OK — type is 'bar', not string
}
// Fix 2 (recommended): write the literal inline
const options: ApexOptions = {
chart: { type: 'bar' }, // OK — no widening possible
}
Inline literals are preferred because they are self-contained and do not require the reader to find the variable declaration to know the type.
The full set of valid chart type strings is:
type ChartType =
| 'line'
| 'area'
| 'bar'
| 'pie'
| 'donut'
| 'radialBar'
| 'scatter'
| 'bubble'
| 'heatmap'
| 'candlestick'
| 'boxPlot'
| 'radar'
| 'polarArea'
| 'rangeBar'
| 'rangeArea'
| 'treemap'
Formatter function types
Formatter callbacks used in yaxis.labels, xaxis.labels, and tooltip are typed in the definitions. You can annotate them explicitly or rely on inference from ApexOptions:
import type { ApexOptions } from 'apexcharts'
const options: ApexOptions = {
yaxis: {
labels: {
// value is number; must return string
formatter: (value: number): string => '$' + value.toFixed(0),
},
},
tooltip: {
y: {
// opts contains series index, data point index, and other context
formatter: (value: number, opts?: object): string =>
'$' + value.toLocaleString(),
},
},
}
If you store a formatter in a variable before using it, annotate the function type explicitly so TypeScript does not infer unknown for the parameters:
const currencyFormatter = (value: number): string => '$' + value.toFixed(2)
const options: ApexOptions = {
yaxis: { labels: { formatter: currencyFormatter } },
}
React typed example
react-apexcharts ships its own TypeScript definitions and you pass ApexOptions directly to its options prop. Install both packages:
npm install react-apexcharts apexcharts
A complete typed component:
import ReactApexChart from 'react-apexcharts'
import type { ApexOptions } from 'apexcharts'
import type { ApexAxisChartSeries } from 'apexcharts'
function SalesChart() {
const series: ApexAxisChartSeries = [
{ name: 'Sales', data: [44, 55, 41, 67, 22, 43] },
{ name: 'Returns', data: [13, 23, 20, 8, 13, 27] },
]
const options: ApexOptions = {
chart: {
type: 'bar',
height: 350,
toolbar: { show: false },
},
xaxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
},
yaxis: {
labels: {
formatter: (value: number) => '$' + value.toLocaleString(),
},
},
legend: {
position: 'top',
},
}
return (
<ReactApexChart
type="bar"
series={series}
options={options}
height={350}
/>
)
}
export default SalesChart
Note that type is passed both inside options.chart.type (used by the chart renderer for behavior) and as the type prop on ReactApexChart (used by the wrapper to render the correct SVG structure). They should match.
Angular typed example
ng-apexcharts re-exports the ApexCharts type definitions, so you can import from either package. The apx-chart component accepts the config broken into separate @Input() bindings, which matches the sub-type approach well:
import { Component } from '@angular/core'
import type {
ApexChart,
ApexXAxis,
ApexYAxis,
ApexAxisChartSeries,
ApexTooltip,
} from 'ng-apexcharts'
@Component({
selector: 'app-revenue-chart',
template: `
<apx-chart
[series]="series"
[chart]="chart"
[xaxis]="xaxis"
[yaxis]="yaxis"
[tooltip]="tooltip"
></apx-chart>
`,
})
export class RevenueChartComponent {
chart: ApexChart = {
type: 'area',
height: 350,
zoom: { enabled: false },
}
series: ApexAxisChartSeries = [
{
name: 'Revenue',
data: [31, 40, 28, 51, 42, 109, 100],
},
]
xaxis: ApexXAxis = {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
}
yaxis: ApexYAxis = {
labels: {
formatter: (value: number) => '$' + value.toLocaleString(),
},
}
tooltip: ApexTooltip = {
x: { format: 'MMM' },
}
}
Each property is individually typed, so Angular's template compiler can check the bindings and your IDE gives accurate completions for each section.
Strict mode and DOM queries
With "strict": true in tsconfig.json, document.querySelector('#chart') returns Element | null. Passing that directly to new ApexCharts() is a type error because the constructor requires a non-null element.
Use a type-parameterized query and an explicit guard:
import ApexCharts from 'apexcharts'
import type { ApexOptions } from 'apexcharts'
const options: ApexOptions = {
chart: { type: 'line', height: 350 },
series: [{ name: 'Sales', data: [30, 40, 35, 50, 49] }],
xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May'] },
}
// querySelector<T> narrows the return type to T | null
const el = document.querySelector<HTMLDivElement>('#chart')
if (!el) {
throw new Error('Chart container #chart was not found in the DOM')
}
// el is now HTMLDivElement, not null — safe to pass
const chart = new ApexCharts(el, options)
chart.render()
The non-null assertion (!) is a shorter alternative but gives no runtime protection. The guard approach is safer in production code because it surfaces misconfiguration as a clear error rather than a silent crash.