Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import esm modules with NodeJS 13, and Typescript 3.8?

I have a problem with some imports in NodeJS. I want to use the new features of Typescript 3.8, like private fields : #myPrivateField

I don't know how to correctly import the module "typescript" in my class. I tried many options, but impossible to solve my problem.

My files :

package.json

{
  "name": "test",
  "scripts": {
    "start": "tsc && node --experimental-modules --es-module-specifier-resolution=node main.js"
  },
  "dependencies": {
    "@types/node": "^13.13.2",
    "app-root-path": "^3.0.0",
    "fs-extra": "^9.0.0",
    "tsutils": "^3.17.1"
  },
  "devDependencies": {
    "ts-node": "~8.3.0",
    "typescript": "^3.8.3"
  },
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "lib": [
      "ESNext",
      "es2016",
      "dom",
      "es5"
    ],
    "module": "esnext",
    "moduleResolution": "Node",
    "sourceMap": true,
    "target": "es6",
    "typeRoots": [
      "node_modules/@types"
    ]
  }
}

main.ts

// import ts = require("typescript");
import * as ts from "typescript";

export class Main {

    node: ts.Node;
    #test = 'zzz';

    constructor() {}

    process(): void {
        ts.forEachChild(this.node, function cb() {
        });
        console.log('#test', this.#test);
    }
}

const main = new Main();
main.process();

With this code, when I run npm run start, I have the error TypeError: ts.forEachChild is not a function

Without the line with ts.forEachClid() it logs correctly the value of the private field #test.

If I try to replace import * as ts from "typescript"; by import ts = require("typescript");, I have the error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead

Of course, I tried many changes in tsconfig.json and in package.json (with `"type" = "module"), but impossible to solve this problem.

I even tried to replace "module": "esnext" by "module": "commonjs", but I have an error exports is not defined.

Remark : This is not specific to the module "typescript". I have the same problem with other modules like "fs-extra", which are making exports in a different way than most of classic NodeJS modules.

For example, the module "typescript" exports with export = ts.

I found this reference too, but it didn't help me a lot : https://www.typescriptlang.org/docs/handbook/modules.html

My nodeJs version is 13.3.0 and my typescript version is 3.8.3 Thanks for your help

like image 469
Gilles Fabre Avatar asked Nov 15 '22 12:11

Gilles Fabre


1 Answers

Finally, the good response was : you need commonjs and es2018 to be able to use the typescript #privateFields in a node module.

Here is the correct tsconfig.json to use :

{
    "compileOnSave": false,
    "compilerOptions": {
        "module": "commonjs",
        "moduleResolution": "node",
        "target": "es2018",
        "typeRoots": [
            "node_modules/@types"
        ],
        "lib": [
            "es2018",
            "dom"
        ]
    }
}
like image 189
Gilles Fabre Avatar answered Dec 25 '22 18:12

Gilles Fabre