'import mathjax throws error @types/mathjax/index.d.ts is not a module

I'm trying to import MathJax in a TypeScript file.

You can repro with the following steps:

tsc --init
npm init -y
npm i mathjax @types/mathjax
echo "import { MathJax } from 'mathjax';" > index.ts

I've tried all of the following important syntaxes:

import { MathJax } from 'mathjax';
import mathjax from "mathjax";
import * as mathjax from "mathjax"
import { * as MathJax } from "mathjax";

But all return the following error:

'../node_modules/@types/mathjax/index.d.ts' is not a module.

I've also tried adding mathjax to types in my tsconfig.app.json like this (but that hasn't helped either)

"types": [
   "mathjax"
]

Related Problems



Solution 1:[1]

This answer is written with the use of MathJax in a web project in mind. If this is not the case for you, much of it still applies since it relates to Typescript, which you clearly use.

1. MathJax is meant to be downloaded in the browser

No matter the situation today, MathJax is historically downloaded in the browser and should not be imported into a project targeting the web like other npm packages. Under Installation and use at https://www.npmjs.com/package/mathjax you can see that you're only supposed to use MathJax in a project like this if you're making a backend Node application, otherwise MathJax should be imported in the frontend with a script. You can host your own MathJax copy as a static file resource on your web server and load it from there in a script tag from the frontend (much like any CDN), but you shouldn't build it into the frontend like you do with regular npm packages by importing it into the source files. Why does this matter ? Because it affects how MathJax is organized, both historically and today, which in turn affects how it is treated in a Typescript project.

2. MathJax packages

MathJax has two versions, MathJax 2 and 3. 2 is very different from version 3 internally and syntactically but is still used even though version 3 is recommended. The package mathjax from npmjs.org is the MathJax 3 package. If you go to the MathJax Github repo, you can download older packages but I don't think they're available as npm packages. On the official MathJax page under Server integration you can read about how to download MathJax in the backend. You also see there that there are two npm packages: mathjax and mathjax-full of which the latter contains the "full source code". MathJax is written with Typescript support so we can expect that there are types. If you visit the npmjs.org entries for these packages (https://www.npmjs.com/package/mathjax and https://www.npmjs.com/package/mathjax-full), you see that mathjax-full contains types which mathjax does not. This can also be seen by expecting the downloaded packages in node_modules.

So what is the package @types/mathjax? Well, upon inspection, we can see that it is connected to MathJax version 2, because its type declarations involve the use of MathJax.Hub which is only used in version 2. Also its index.d.ts, the entrypoint for types when nothing more specific is indicated than

import mathjax from "mathjax"

or

import * as mathjax from "mathjax"

declares a namespace with exports inside of it

declare namespace MathJax {
    export ...
    export ...
}

Namespaces are used in Javascript to organize code into different disjoint components, a sort of earlier alternative to modules, which do the same things without namespaces. In the Typescript documentation (https://www.typescriptlang.org/docs/handbook/modules.html) it literally says that In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. The package @types/mathjax doesn't have that, which results in it not being a module which also your compiler reports.

So except for the fact that @types/mathjax is not connected to the npm package mathjax (which is bad organization I know) due to different versions, it also doesn't support modern module syntax. I would say that it's old too but it had a release quite recently so to be frank, I don't know what it's about, perhaps it has something to do with how MathJax is usually imported or it's supposed to work in some other very particular situation. All I know is that according to the Typescript documentation, this types package is not considered a module (as indicated by your compiler) and its types do not align with MathJax version 3, e.g. I definitely don't think that there is an official affiliation between this package and the package which it is supposed to support.

So given mathjax-full we have types, right? Yes, that is true, but the file organization in mathjax-full is not adapted to your use-case. First of all, it lacks an index, so there is no reasonable entrypoint to use for the kind of import statements earlier described (as said, when no specific resource is targeted, the natural entrypoint is the index file). The package.json included does not contain neither package information nor information about types (you can check this for yourself in node_modules). Even when I try to use it without Typescript, it doesn't work due to errors about require not being defined. All in all, this package is not meant to be used like the average npm package that you use; it should be used for those who wish to work with the source code of MathJax and definitely not in the "average-user-building-a-web-application" use-case. For those, MathJax should be used as a separate black box project that is accessed via a script import (again, due to historical reasons.. this was the way things were 15 years ago or so).

3. How to make it work in your use-case

To make it work in your use-case, and by that I mean to make your compiler accept your import (nothing else), there are a few things you can do. I say this because I sense an interest in how Typescript works here as well.

In the case of the @types/mathjax package, you can go into its index.d.ts in node_modules and add export default MathJax at the bottom (top-level). Now the file has a global export and therefore, import statements like

import * as mathjax from "mathjax"
import mathjax from "mathjax"

will not result in the complaints you saw earlier. It would still not work though because of the require errors I briefly described earlier.

In the case of mathjax-full, by inspecting the code in node_modules you can see that there are indeed Typescript files along the source code in the js sub directory. But since no index is present (also a clear hint that the package should not be used in web projects by means of imports), default imports won't work (compiler will complain about types). If you however target a particular asset, for example

import { mathjax } from "mathjax-full/js/mathjax"

it will find the corresponding types and you will not get an error. You actually get some sort of MathJax object then but I don't know if it would work all the way (try it if you want to). Besides, I suspect you would get quite a lot of extra unneeded files in your bundle (or have to spend a lot of time on customizing tree-shaking) since MathJax is used to determine what files it needs upon usage and it might be hard for the bundler to determine this at build time.

4. So how should you REALLY fix this?

The best way is to use a React package for MathJax. Here I will recommend my own package better-react-mathjax (https://www.npmjs.com/package/better-react-mathjax) but there are others as well. Such packages have tried to bridge the gap between MathJax and React, like the one you are experiencing now.

If you want to do it the more complicated way, you use the source code in the MathJax packages and include them as part of your static files resources, and you then inject a script tag in React that fetches the file with the MathJax start script from your static backend. You could also do it this way and fetch the same file from a CDN if you don't want to host your own copy.

If you really need to use MathJax in the backend, I would investigate the mathjax-full package and try to convert the instructions about using it in Node in the official MathJax docs earlier pointed to, to your usecase, working with explicit imports instead of default ones to get type support.

Recommendations

I detect a certain interest in code organization and modules (perhaps mistakenly) on your behalf which is a complicated subject. Try writing your own package and distribute it via npm to get an understanding of the roles played by npm, Node, Typescript, ecmascript modules, commonjs modules and so on. Understanding the different module formats and how they are allowed to interact in Typescript projects using features like esModuleInterop and allowSyntheticDefaultImports are also important topics and by distributing your own package, you will really get an idea about the differences of source code in a project, and source code in packages.

Solution 2:[2]

Simply import the typings library:

import "mathjax";

use the "types": ["mathjax"] compiler option.

link: reference link

Hope this will work for you!!

Solution 3:[3]

This works: import * as MathJax from 'mathjax';

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 ps0604