[Cross-posted to https://github.com/chartjs/Chart.js/discussions/10864].
I'm using Chart.js with React and TypeScript. Following this answer, I've typed my custom plugin options in an index.d.ts
-file, like so:
export type MyPluginOptions = {
foo: string;
bar: string;
};
declare module 'chart.js' {
interface PluginOptionsByType<TType extends ChartType> {
myPlugin?: MyPluginOptions;
}
}
The problem is that Chart.js has this wrapped (I think) in a _DeepPartialObject<>
, which means that foo
and bar
become optional against my intention. Can I somehow counteract this, or how should I deal with it? I would like all keys to be required. I feel like I should be able to utilize TypeScipt's Required<>
somehow, but I can't seem to figure out how.
For more context, I then have something like this defined:
const myChartOptions: ChartOptions<'bar'> = {
// other options,
plugins: {
myPlugin: {
foo: 'something',
bar: 'something else',
},
},
};
Here TypeScript is fine with foo
and/or bar
missing. Then, when defining the action of the plugin, one thing I've tried looks something like:
const myPlugin : Plugin<'bar'> = {
id: 'my-plugin',
afterDraw: function (chart, _args, options: MyPluginOptions) {
if (options) {
const x = options.foo;
const y = options.bar;
// more code
};
};
Since I "cheated" by writing options: MyPluginOptions
, TypeScript infers that foo
and bar
exist. But it also infers that options
exists, which it could not, so that's can be a problem. Alternatively, I could have
const myPlugin : Plugin<'bar'> = {
id: 'my-plugin',
afterDraw: function (chart) {
const options = chart.plugins?.myPlugin as MyPluginOptions;
if (options) {
const x = options.foo;
const y = options.bar;
// more code
};
};
This mostly gives me what I want, but doesn't provide non-partial type checking when setting the options.
Other workarounds I can image include:
- Setting the options in an unrelated object to circumvent the Chart.js typing entirely.
- Actually treating them as optional keys and define default behavior on undefined keys. (Seems unnecessary in my use case, but I suspect this is the intention of the Chart.js team?).
I would love to get some more insight, especially if I'm missing the mark on the preferred way to do things.