Turns out it was something really obvious: you had to use the --allowJs option. This worked for me:

tsc --moduleResolution "node" --module "commonjs"  --allowJs main.ts

Though, I still can't figure out why d3 worked while the others libraries didn't.

Answer from Federico on Stack Overflow
🌐
TypeScript
typescriptlang.org › docs › handbook › 2 › modules.html
TypeScript: Documentation - Modules
There is a mis-match in features between CommonJS and ES Modules regarding the distinction between a default import and a module namespace object import. TypeScript has a compiler flag to reduce the friction between the two different sets of constraints with esModuleInterop.
Discussions

Importing commonJS modules with es6 imports
QuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code ... I'm trying to convert a Babel project with typescript and I realize that I need to change some of the imports from import module from 'module' to import * as module from 'module' to ... More on github.com
🌐 github.com
13
September 27, 2016
ES module can import but can't export from a common js module?
I don't know the specifics on why import works & export does not. But CJS & ESM interop is a horrible mess. I'd just do what it says. import pkg from 'aws-sdk/lib/credentials.js'; export const { Credentials } = pkg More on reddit.com
🌐 r/typescript
8
0
July 30, 2024
It is very difficult to call the `import` function from a CommonJS module.
It is going to take a long time ... an ESM modules on targets that support it? I don't want to get into the ESM/CommonJS debacle. My goal here is to just to async import an ESM Module from CommonJS TypeScript.... More on github.com
🌐 github.com
9
February 15, 2023
node.js - Why won’t TypeScript let me import a type from an ES module into a CommonJS module? - Stack Overflow
I’m writing a Node.js app in TypeScript. Here’s a simplified version of my files so far: ... error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. More on stackoverflow.com
🌐 stackoverflow.com
🌐
TypeScript
typescriptlang.org › docs › handbook › modules › appendices › esm-cjs-interop.html
TypeScript: Documentation - Modules - ESM/CJS Interoperability
So while the flag enabled more accurate checking as long as the code was fed into another tool like Babel or Webpack, it created a real danger for users who were emitting --module commonjs with tsc and running in Node.js. If they encountered an error with import *, it may have appeared as if enabling allowSyntheticDefaultImports would fix it, but in fact it only silenced the build-time error while emitting code that would crash in Node. TypeScript introduced the esModuleInterop flag in 2.7, which refined the type checking of imports to address the remaining inconsistencies between TypeScript’s analysis and the interop behavior used in existing transpilers and bundlers, and critically, adopted the same __esModule-conditional CommonJS emit that transpilers had adopted years before.
🌐
JavaScript in Plain English
javascript.plainenglish.io › how-to-correctly-use-typescript-module-import-syntax-and-settings-in-various-circumstances-e98bfa87f70f
How to Correctly Use TypeScript Module Import Syntax and Settings in Various Circumstances | by Bing Ren | JavaScript in Plain English
June 24, 2021 - (3) MODULE: the “module” option in tsc settings (set in tsconfig.json or through command-line argument), takes the values of “commonjs” (instructing tsc to emit CommonJS import statements, e.g. “require()”) or “es2020”. “es2015”, “es2020” or higher settings instruct tsc to emit ES Module import statements. “es2015” produces the same result as “es2020”, however, this option does not support dynamic import. See tsconfig.json reference for more about this option. (4) CASE: the test cases in which different Typescript import syntaxes are used.
🌐
GitHub
github.com › microsoft › TypeScript › issues › 11179
Importing commonJS modules with es6 imports · Issue #11179 · microsoft/TypeScript
September 27, 2016 - 'use strict'; var _module = require('module'); var _module2 = _interopRequireDefault(_module); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } console.log(_module2.default); ... Which logs undefined when importing a classic commonJS module. Maybe Typescript is right here but the glue Babel provides appends to be pretty convenient.
Author   testerez
🌐
TypeScript
typescriptlang.org › docs › handbook › modules › reference.html
TypeScript: Documentation - Modules - Reference
CommonJS emit leaves dynamic import() calls untransformed, so CommonJS modules can asynchronously import ES modules. In --module preserve (added in TypeScript 5.4), ECMAScript imports and exports written in input files are preserved in the output, and CommonJS-style import x = require("...") ...
🌐
Reddit
reddit.com › r/typescript › es module can import but can't export from a common js module?
r/typescript on Reddit: ES module can import but can't export from a common js module?
July 30, 2024 -

I wrote this line in my code

export { Credentials } from 'aws-sdk/lib/credentials.js'; // "aws-sdk": "^2.955.0",

It can be built without any problem, but at run time I got:

Exception during run: file:///x/src/index.js:1
export { Credentials } from 'aws-sdk/lib/credentials.js';
         ^^^^^^^^^^^
SyntaxError: Named export 'Credentials' not found. The requested module 'aws-sdk/lib/credentials.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'aws-sdk/lib/credentials.js';
const { Credentials } = pkg;

But I have no problem using it like this:

import { Credentials } from 'aws-sdk/lib/credentials.js';

Since this is an npm package, I have to export Credentials. What's the best practice?

🌐
TypeStrong
typestrong.org › ts-node › docs › imports
CommonJS vs native ECMAScript modules | ts-node
TypeScript is almost always written ... by the underlying runtime. You can choose to either transform to CommonJS or to preserve the native import syntax, using node's native ESM support. Configuration is different for ...
Find elsewhere
🌐
Medium
medium.com › ag-grid › understand-packaging-for-javascript-typescript-commonjs-and-everything-else-1fe835f3243a
Understand Packaging for Javascript, TypeScript, CommonJS and Everything Else | by Niall Crosby | AG Grid | Medium
June 4, 2021 - External modules in TypeScript are what you see in ag-Grid and Angular 2 code and this is what works best with CommonJS as it gets compiled down to CommonJS ‘require’ functions which is what most of the rest of the world is using, incluing the React community. /* Include your references like this*/ import {MyUtils} from './MyUtils' />/* No modules, the file name and location provide the equivalent */ export class Grid { ...
🌐
GitHub
github.com › microsoft › TypeScript › issues › 52775
It is very difficult to call the `import` function from a CommonJS module. · Issue #52775 · microsoft/TypeScript
February 15, 2023 - /** * Thunk Layer for `import` to allow dynamic imports. * @param {string | URL} module - name of module to load * @returns */ export function dynamicImport(module: string): Promise<any>; If I add that code into my CommomJS TypeScript project with allowJs, import gets converted into require, even if the target is ES2020.
Author   Jason3S
🌐
vimtutor
remarkablemark.org › blog › 2020 › 05 › 05 › typescript-export-commonjs-es6-modules
TypeScript export CommonJS and ES Modules | remarkablemark
May 5, 2020 - // CommonJS const myModule = require('./index'); // ES Modules import myModule from './index';
🌐
Evertpot
evertpot.com › universal-commonjs-esm-typescript-packages
Supporting CommonJS and ESM with Typescript and Node
For this I had 2 approaches: Either reconfigure mocha to use the CommonJS Typescript loader instead of the ESM typescript loader, but this was too much of a pain to get right with writing configuration files on the fly. Instead, I decided to just ask Typescript to build the entire project including tests in a separate directory and then just run Mocha on the javascript files. mkdir -p cjs-test cd test; npx tsc --module commonjs --outdir ../cjs-test echo '{"type": "commonjs"}' > cjs-test/package.json cd cjs-test; npx mocha --no-package
🌐
DigitalOcean
digitalocean.com › community › tutorials › how-to-use-modules-in-typescript
How To Use Modules in TypeScript | DigitalOcean
February 7, 2022 - 1 import Vector2 = require("./vector2"); To learn more about targeting the ES module system, take a look at the TypeScript Compiler documentation for the module property. TypeScript offers a fully-featured module system with syntax inspired by the ES module specification, while allowing the developer to target a variety of other module systems in the emitted JavaScript Code, like CommonJS, AMD, UMD, SystemJS, and ES6.
🌐
TypeScript
typescriptlang.org › docs › handbook › modules.html
TypeScript module documentation
April 11, 2023 - Find TypeScript starter projects: from Angular to React or Node.js and CLIs.
Top answer
1 of 1
14

Is this a bug? Kind of.

The error message is indeed confusing and misleading—you’re correct that there is no runtime representation of an import type statement, so the fact that the error message says it will become a require call and suggests writing a dynamic import is a bug. However, this code is intended to have an error. In TypeScript 5.7, the error message was updated to say

Type-only import of an ECMAScript module from a CommonJS module must have a 'resolution-mode' attribute.

...which doesn’t answer the question of why the import is an error, which I’ll come back to, but it does answer your next question:

Is there a workaround? Yes!

Since TypeScript 5.3, the error can be silenced by adding a resolution-mode import attribute:

import type { Options } from "./types.ts" with { "resolution-mode": "import" };

or, in type import form:

const options: import("./types.ts", { with: { "resolution-mode": "import" } }) = {};

The resolution-mode import attribute, which is only supported on type-space imports, tells the TypeScript compiler whether to resolve the module specifier like Node.js would resolve a CommonJS require or an ESM import, which use completely separate module resolution algorithms. (In this example, both "require" and "import" would work because the module specifier is a relative path including the file extension. If the module specifier had been "./types", only "require" would work, since the Node.js ESM module resolution algorithm does not support omitting file extensions on relative paths.)

Why is this an error?

Instead of the example with "./types.ts", imagine that the error came from an import of a third-party dependency that ships only ESM code:

// processOptions.cts
import type { Options } from "remark-mdx";

Since the importing file is .cts, this type-only import resolves using the require algorithm, but it resolves to an ES module—remark-mdx does not contain any CommonJS. Now suppose that the authors of remark-mdx decided to begin shipping a CommonJS build alongside the ESM in the package, using package.json conditional "exports". Adding a conditionally loaded legacy build should be a backward compatible change, right? Well, not for the type checking of processOptions.cts. If remark-mdx adds new types that resolve under the require algorithm in a patch bump, that could change the type of Options. But if we explicitly specify with { "resolution-mode": "import" }, we can be pretty sure that our code will be unaffected by remark-mdx’s hypothetical decision to add a CommonJS entrypoint.

This concern is about protecting the ability of external package authors to make backward-compatible changes via package.json "exports". It really doesn’t apply at all to relative imports of your own files that you control. However, it was decided that, for consistency, the error should not be conditional on whether the import module specifier is relative. There is a lot of discussion about this on the TypeScript issue tracker, linked from the PR that changed the error message.

🌐
2ality
2ality.com › 2020 › 04 › npm-cjs-typescript.html
Creating CommonJS-based npm packages via TypeScript
April 16, 2020 - We only import CommonJS modules. Especially on Node.js, TypeScript currently doesn’t really support ECMAScript modules and filename extensions other than .js. This is how the repository ts-demo-npm-cjs is structured: ts-demo-npm-cjs/ .gitignore .npmignore dist/ (created on demand) package.json ...
🌐
Runebook.dev
runebook.dev › en › docs › typescript › docs › handbook › modules › reference › commonjs
Mastering CommonJS in TypeScript: Solutions for Module Resolution Errors
The Fix Be consistent. If your project is CommonJS, stick to require() for simplicity and to avoid confusion, especially when debugging. If you want to use the modern import syntax, consider migrating your project to ES Modules.