title: How to have type transfer of ChartJS configuration from a react component prop?
body: <p>I made a <code>ChartJS</code> component that is a simple react wrapper to correctly setup and destroy ChartJS instances with some default options:</p>
  <pre class="lang-js prettyprint-override"><code>import React, {
    useEffect,
    useState,
    VFC,
  } from 'react';
  import {
    ArcElement,
    BarController,
    BarElement,
    CategoryScale,
    Chart,
    ChartConfiguration,
    DoughnutController,
    LinearScale,
  } from 'chart.js';
  
  Chart.register(
    ArcElement,
    BarElement,
    BarController,
    DoughnutController,
    CategoryScale,
    LinearScale,
  );
  
  export interface ChartJSProps {
    config: ChartConfiguration;
  }
  
  export const ChartJS: VFC&lt;ChartJSProps&gt; = ({
    config,
  }) =&gt; {
    const [id, setId] = useState&lt;string&gt;();
  
    useEffect(() =&gt; {
      setId(`chart-${Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)}`);
    }, []);
  
    useEffect(() =&gt; {
      if (!id) {
        return;
      }
  
      // @see https://stackoverflow.com/a/58877962/1731473
      const canvas: HTMLCanvasElement = document.getElementById(id) as HTMLCanvasElement;
      const ctx = canvas.getContext('2d');
      let chart: Chart;
      if (ctx !== null) {
        const { options } = config;
        chart = new Chart(ctx, {
          ...config,
          options: {
            responsive: true,
            maintainAspectRatio: false,
            ...options,
            elements: {
              ...options?.elements,
              line: {
                fill: false,
                ...options?.elements?.line,
              },
            },
            plugins: {
              ...options?.plugins,
              legend: {
                display: false,
                ...options?.plugins?.legend,
              },
              tooltip: {
                mode: 'nearest',
                intersect: false,
                ...options?.plugins?.tooltip,
              },
            },
          },
        });
      }
  
      return () =&gt; {
        if (chart) {
          // @see https://www.chartjs.org/docs/latest/developers/api.html#destroy
          chart.destroy();
        }
      };
    }, [id]);
  
    return (
      &lt;canvas id={id} /&gt;
    );
  };
  
  export default null;
  </code></pre>
  <p>This wrapper is fully working, however, Typescript is yelling about type specific configuration.</p>
  <p>Here is a <code>GaugeChart</code> component using the ChartJS <code>doughnut</code> type as an example:</p>
  <pre class="lang-js prettyprint-override"><code>import React, {
    VFC,
  } from 'react';
  import { ChartJS } from './ChartJS';
  
  export interface GaugeChartProps {
    value: number;
    max?: number;
  }
  
  export const GaugeChart: VFC&lt;GaugeChartProps&gt; = ({
    value,
    max = 100,
  }) =&gt; {
    const percent = value / max;
  
    return (
      &lt;ChartJS config={{
        type: 'doughnut',
        data: {
          datasets: [
            {
              backgroundColor: [
                'rgb(255, 99, 132)',
                '#ccc',
              ],
              // eslint-disable-next-line id-blacklist
              data: [
                percent * 100,
                100 - (percent * 100),
              ],
            },
          ],
        },
        options: {
          rotation: 270, // start angle in degrees
          circumference: 180, // sweep angle in degrees
        },
      }}
      /&gt;
    );
  };
  
  export default null;
  </code></pre>
  <p>The <code>npx tsc</code> command give me this:</p>
  <pre><code>src/components/chart/GaugeChart.tsx:36:9 - error TS2322: Type '{ rotation: number; circumference: number; }' is not assignable to type '_DeepPartialObject&lt;CoreChartOptions&lt;keyof ChartTypeRegistry&gt; &amp; ElementChartOptions&lt;keyof ChartTypeRegistry&gt; &amp; PluginChartOptions&lt;...&gt; &amp; DatasetChartOptions&lt;...&gt; &amp; ScaleChartOptions&lt;...&gt;&gt;'.
    Object literal may only specify known properties, and 'rotation' does not exist in type '_DeepPartialObject&lt;CoreChartOptions&lt;keyof ChartTypeRegistry&gt; &amp; ElementChartOptions&lt;keyof ChartTypeRegistry&gt; &amp; PluginChartOptions&lt;...&gt; &amp; DatasetChartOptions&lt;...&gt; &amp; ScaleChartOptions&lt;...&gt;&gt;'.
  
  36         rotation: 270, // start angle in degrees
             ~~~~~~~~~~~~~
  
    node_modules/chart.js/types/index.esm.d.ts:3493:3
      3493   options?: ChartOptions&lt;TType&gt;;
             ~~~~~~~
      The expected type comes from property 'options' which is declared here on type 'ChartConfiguration&lt;keyof ChartTypeRegistry, (number | ScatterDataPoint | BubbleDataPoint | null)[], unknown&gt;'
  </code></pre>
  <p>Typescript Version:</p>
  <pre><code>❯ npx tsc -v
  Version 4.2.2
  </code></pre>
  <p>As you can see, the <code>rotation</code> option is not recognized.</p>
  <p>Of course, I could resolve it by declaring a well typed constant:</p>
  <pre class="lang-js prettyprint-override"><code>import React, {
    VFC,
  } from 'react';
  import { ChartConfiguration } from 'chart.js';
  import { ChartJS } from './ChartJS';
  
  export const GaugeChart: VFC&lt;GaugeChartProps&gt; = ({
    value,
    max = 100,
  }) =&gt; {
    const percent = value / max;
    const config: ChartConfiguration&lt;'doughnut'&gt; = {
      type: 'doughnut',
      data: {
        datasets: [
          {
            backgroundColor: [
              'rgb(255, 99, 132)',
              '#ccc',
            ],
            // eslint-disable-next-line id-blacklist
            data: [
              percent * 100,
              100 - (percent * 100),
            ],
          },
        ],
      },
      options: {
        rotation: 270, // start angle in degrees
        circumference: 180, // sweep angle in degrees
      },
    };
  
    return &lt;ChartJS config={config} /&gt;;
  };
  </code></pre>
  <p>But it means I have to rely directly to the <code>chart.js</code> vendor, it looks not ideal.</p>
  <p>Also, the <code>type</code> configuration value should infer to the <code>options</code> defintion, as it is done with a simple <code>new Chart</code> call with direct configuration.</p>
  <p>How can I have the same behavior with <code>type</code> value inference on my component wrapper <code>config</code> prop?</p>