Chart.js icon indicating copy to clipboard operation
Chart.js copied to clipboard

using TypeScript type definitions in code without modules

Open mackuba opened this issue 3 years ago • 9 comments

Do the TS type definitions in Chart.js 3.0 support code written old-school web way, without modules, with the library included in HTML using <script>?

I have a file that uses Chart.js this way, written in TypeScript, and it worked fine with Chart.js 2.x, with the types from DefinitelyTyped. I'm trying to upgrade to 3.0 now, and the TypeScript compiler doesn't seem to recognize the name Chart. I can see it's going through the type files, but in the end it somehow doesn't make this declaration available to my script (error TS2304: Cannot find name 'Chart'.).

I suspect this may be because (as I understand?) the objects are now exported there using the CommonJS way, but I'm not actually importing any modules in my script, since it relies on the Chart object being imported into window earlier. But I have a pretty poor understanding of how JS modules work in general, so I'm not sure.

Based on some simple tests, I can see that a class declared like this (which is how type declarations for Chart.js 2.x looked like) works when used without an import:

declare class Chart {
  id: string;
}

But a class declared like this (which is how type declarations for Chart.js 3.x look like) doesn't:

export declare class Chart {
  id: string;
}

I've found some suggestions on the web that adding a wrapper script that imports the contents of the module and then re-exports everything using declare global could fix this, but I've tried a few different ways and nothing seems to give the results I want.

Given that Chart.js 2.x could be used this way, and Chart.js 3.x supports being used this way in plain JS (using the non-ESM variant of the build from a CDN), is this something you could possibly add? Or at least, can you provide tips on how to work around this on the user side, if that's actually possible?

Steps to Reproduce

  • have a .ts file that references the Chart class from the global namespace without using import
  • add type declaration files from the types folder into the project, or install chart.js to node_modules using npm
  • run the TypeScript compiler with npx tsc on that TypeScript file

Expected Behavior

The TypeScript compiler should load all type definitions for Chart.js. When parsing a TS file that uses Chart.js 2.x, it should only print errors for the parts of code that call APIs that have been removed in 3.x.

Current Behavior

The TypeScript compiler seems to load type definitions (npx tsc --traceResolution shows it's going through the files), but it still doesn't recognize any APIs from Chart.js:

error TS2304: Cannot find name 'Chart'.
error TS2503: Cannot find namespace 'Chart'.

Environment

  • Chart.js version: 3.6.1
  • TypeScript compiler version: 4.4.3

mackuba avatar Dec 06 '21 17:12 mackuba

So lets see if I understand correctly:

  • You have a .html (or equivalent) file referencing chart.js with script tag.
  • You have a TS project that you compile and reference the result in another script tag
  • You expect tsc to know about global Chart without importing it?

kurkle avatar Dec 08 '21 14:12 kurkle

More or less, yeah. This used to work with Chart.js 2.9.3 from which I'm upgrading, with type definitions from @types/chart.js (https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/chart.js), which were defined in a global context (declare class Chart). As I understand, in this setup the TypeScript compiler somehow automatically finds relevant type definitions without the need for any explicit imports.

With 3.x I tried adding an explicit TypeScript types import like this:

/// <reference types="chart.js" />

which makes the compiler step through all provided type files (as seen when run with --traceResolution), but in the end it still doesn't understand the name Chart.

Here's a sample project:

  • https://github.com/mackuba/chartjs_sample - 2.x - npx tsc works
  • https://github.com/mackuba/chartjs_sample/tree/chartjs_v3 - 3.x - npx tsc says Cannot find name 'Chart'.

mackuba avatar Dec 08 '21 16:12 mackuba

@mackuba if I remember correctly, the /// <reference is looking for types in the @types folder. So you need to write a simple script to copy the chartjs types.

xr0master avatar Dec 08 '21 20:12 xr0master

I don't think it's an issue of it not finding the files, I think it's that the types are exported in the module way and the TS compiler doesn't understand "Chart" used in the global scope. If I understand this correcly.

This is the log from npx tsc --traceResolution when I add the <reference>, take a look: https://gist.github.com/mackuba/e98e6278a474a686c932b159ababfac6

mackuba avatar Dec 08 '21 20:12 mackuba

Maybe you can use the import type {Chart} from 'chart.js' pattern to work around this? (I'm writing on mobile, so too hard to test)

kurkle avatar Jan 12 '22 04:01 kurkle

@kurkle not without many more changes - if I add that, tsc starts complaining about the properties I add to Window, and global functions that are called from HTML, and so on… and then that import gets printed to the resulting JS, and the browser fails to load it at all. I would have to switch the whole JS to module style, but I don't want to do that, I want to keep using it in the classic non-module way like before in 2.x.

mackuba avatar Jan 13 '22 21:01 mackuba

@mackuba You could augment the window interface (see link for reference)

GideonMax avatar Nov 29 '22 11:11 GideonMax

Hi, we would love to have this feature too. The change is very simple, it's enough to add one line at the end of index.d.ts export as namespace chartjs; Link to typescript documentation : export as namespace chartjs;

Thanks

vborioni-onit avatar Apr 03 '23 13:04 vborioni-onit

Here's a workaround that you can use until this is fixed:

Create your own .d.ts file, and add these lines:

import * as _chart from 'chart.js';
export = _chart.Chart;
export as namespace Chart;

RudeySH avatar Dec 14 '23 16:12 RudeySH