Over many years I've struggled with this same issue. I cannot seem to work out how to use a JavaScript library from TypeScript, reliably.
I seem to get it working by accident and then move on and not revisit such code for years until a extrinsic change forces a breakage, like today when I updated VS 2019.
I've spent days reading about modules and requires and loaders, but I get more and more confused.
Example. I want to use DayJS in a TypeScript .ts file I am writing.
Here's the sample code.
import * as dayjs from 'dayjs'
dayjs().format()
The thing I can't understand is that this syntax has never worked for me with any library for two reasons:
- It omits the path to the
dayjsfolder, for me it should belib/dayjs - It doesn't specify a file, and my previous working reference to
moment.jswas pointed at themoment.jsfile.
It's not clear whether 'dayjs' is a folder or a file.
Two issues that compound learning are:
- TypeScript gives the same error whether it's found something but cannot find anything to load, or whether the path is invalid/nonexistent.
error TS2307: Cannot find module 'lib/dayjs' or its corresponding type declarations.
TypeScript seems to allow the import to point to a file without a file extension, for example, this code seems to satisfy and silence the error above, because on disk there is an
index.jsfile. This "flexibility" leads to ambiguity and confusion.import * as dayjs from "lib/dayjs/index";
The TypeScript documentation itself doesn't give an example of importing from a JavaScript library, only from other .ts files, which it does without the extension.
Here are the DayJS files on disk.
lib\dayjs\esm
lib\dayjs\locale
lib\dayjs\plugin
lib\dayjs\CHANGELOG.md
lib\dayjs\dayjs.min.js
lib\dayjs\index.d.ts
lib\dayjs\locale.json
lib\dayjs\package.json
lib\dayjs\README.md
The following syntax gives no error, TypeScript compiles it and even loads intellisense/documentation.
import * as dayjs from "lib/dayjs/index.d.js";
But that file doesn't exist! So my web app doesn't work because Chrome can't get it. But the following doesn't compile, even though the file exists!!
import * as dayjs from "lib/dayjs/index.d.ts";
error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing 'lib/dayjs/index' instead.
However, when I do what the error suggests, well again that's a 404 for Chrome.
Does anyone know what on Earth is going on??
What's the definitive way to use a JavaScript library in TypeScript?
Update
I have now used the baseUrl and paths settings in tsconfig.json to get an import statement compiling in TypeScript which transpiles to a path that is 200 OK when deployed/hosted.
"compilerOptions": {
"target": "es5",
"module": "es2015",
"baseUrl": "./wwwroot/",
"paths": {
"lib/dayjs/dayjs.min.js": [ "lib/dayjs/index" ]
},
...
TypeScript intellisense is telling me that my usage of DayJS is correct.
var f = dayjs().format("dddd D MMMM YYYY");
var t = dayjs(date).format("dddd D MMMM YYYY");
But in the browser, Chrome reports an error:
TimeHelpers.js:16 Uncaught TypeError: dayjs is not a function
I've no clue. I might try moment again, but that gave me some other odd error where global was undefined right at the top of its source code.
Otherwise, apparently I can declare dayjs as Any to satisfy the TS compiler and then use an old-fashioned <script> tag to load it in on the page. This is nuts.
Update
I've made enough progress, by adding the following two lines to my tsconfig.json, and changing to
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
And
import dayjs from "lib/dayjs/dayjs.min.js"
And I now get an error other people are getting which is a relief, because at least I now know to not use DayJS.
https://github.com/iamkun/dayjs/issues/313
Update
Long day today, but some progress was made.
- I've reconfigured
baseUrlandpathsintsconfig.jsonbased on what I've reread and reinterpreted from the docs. - I've switched to trying
luxonbut have problems with that. - VS Code and the compiler see the Luxon typings and intellisense works.
- I've added a small tweak to my
gulpfile.jsto mutate an import path so that Chrome can load it when deployed, works. - Tomorrow I will go back and try moment or one of the others and see if I can apply my new knowledge to get one of those packages working.
I'll post a full explainer when I've got it all working.