I’ve been working with Typescript for some time. We use localization in our frontend web components and we have our own implementation for it.
So, we have a translations folder where we have all the locale files with translations as key value pairs.
We use the locale files to load the translation files based on the language selected by the user from the browser.
And we load the locales like this with a dynamic import:
{
'component': locale => import(`./translations/${locale}.ts`),
},
While everything works fine when we use the extension .js but when we use .ts, tsc wasn’t able to transpile this part of the code.
I would expect the build to be something like this:
{
'component': locale => import(`./translations/${locale}.js`),
},
Does anybody has a clue why that is?
TLDR;
It's not possible to use
.tsextension and have the Typescript compiler change that to.js, as the Typescript compiler itself never modifies module specifiers (that is the path of a module). So, you'll have to provide a.jsextension if you're usingtsc, else, if you really need to use it, you'll need to have some bundler like Webpack or Vite bundle your code, and then transpile it to javascript.ESM in Typescript
ESM (ECMAScript Modules) available in Node version greater than
12.0.0, requires one to specify the extension while importing an ESM module. The same is the case if you use them in a browser. So, we need to add a.jsextension.The Typescript documentation for ESM modules itself specifies to make use of a
.jsextension to get correct runtime file as a rule for using ESM imports. To quote from the Typescript ESM docs -And the reason it is the case, is because Typescript compiler never changes the module specifier. To quote from the Typescript ESM docs -
Which is the reason why it's not changed when you compile it.
Status Quo
There have been many issues created on GitHub for problems that arise out of this and asking for support -
Until there was this proposal and the option
moduleResolutionwas updated with a new optionbundlerwith this PR, which explicitly specifies -Why? Because Typescript compiler itself never modifies the module specifiers, and one needs to be dependent on an external bundler to do that for you.
What can you do?
I'd say just use the
.jsextension, unless you have a very good reason to not to use it (which I doubt there would be one). Otherwise, add themoduleResolutionwithbundleroption andnoEmitwithtruevalues in yourtsconfig.json, along withallowImportingTsExtensionsoption to use the.tsextension and configure a bundler to use with it.