Ts-node : SyntaxError: Cannot use import statement outside a module

Viewed 30164

I was trying to use the top level in the project and saw that it was necessary to change the module from tscofnig to esnext or system, but for some reason my ts-node's error. And I already put the type: module I tried to use the flag: --experimental-modules but the error still does not know how to solve.

package.json:

{
  "name": "micro-hr",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "module",
  "scripts": {
    "commit": "git-cz",
    "build": "babel src --extensions \".js,.ts\" --out-dir dist --copy-files --no-copy-ignored",
    "start:dev": "ts-node-dev --experimental-modules --inspect --respawn --transpile-only --ignore-watch node_modules -r tsconfig-paths/register src/index.ts",
    "start:debug": "node start --debug --watch",
    "start:prod": "node dist/index.ts",
    "test": "jest",
    "lint": "eslint --fix",
    "lint2": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./ormconfig.ts",
    "migration:generate": "ts-node ./node_modules/typeorm/cli.js migration:generate -n"
  },
  "devDependencies": {
    "@babel/cli": "^7.11.5",
    "@babel/core": "^7.11.5",
    "@babel/node": "^7.10.5",
    "@babel/preset-env": "^7.11.5",
    "@babel/preset-typescript": "^7.10.4",
    "@commitlint/cli": "^9.1.2",
    "@commitlint/config-conventional": "^9.1.2",
    "@types/bcryptjs": "^2.4.2",
    "@types/cookie-parser": "^1.4.2",
    "@types/cors": "^2.8.7",
    "@types/express": "^4.17.8",
    "@types/helmet": "^0.0.48",
    "@types/jest": "^26.0.13",
    "@types/node": "^14.6.4",
    "@types/pino": "^6.3.0",
    "@types/pino-http": "^5.0.5",
    "@types/supertest": "^2.0.10",
    "@typescript-eslint/eslint-plugin": "^4.0.1",
    "@typescript-eslint/parser": "^4.0.1",
    "babel-plugin-module-resolver": "^4.0.0",
    "commitizen": "^4.2.1",
    "cz-conventional-changelog": "^3.3.0",
    "eslint": "^7.8.1",
    "eslint-config-airbnb-base": "^14.2.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-config-standard": "^14.1.1",
    "eslint-import-resolver-typescript": "^2.3.0",
    "eslint-plugin-import": "^2.22.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.1",
    "husky": "^4.2.5",
    "jest": "^26.4.2",
    "pino-pretty": "^4.2.0",
    "prettier": "^2.1.1",
    "supertest": "^4.0.2",
    "ts-jest": "^26.3.0",
    "ts-node": "^9.0.0",
    "ts-node-dev": "^1.0.0-pre.62",
    "tsconfig-paths": "^3.9.0",
    "tscpaths": "^0.0.9",
    "typescript": "^4.0.2"
  },
  "dependencies": {
    "amqplib": "^0.6.0",
    "assert": "^2.0.0",
    "bcryptjs": "^2.4.3",
    "class-transformer": "^0.3.1",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "envalid": "^6.0.2",
    "express": "^4.17.1",
    "extendable-error": "^0.1.7",
    "helmet": "^4.1.0",
    "nabbitmq": "^1.0.0",
    "pg": "^8.3.3",
    "pino": "^6.5.1",
    "pino-http": "^5.2.0",
    "reflect-metadata": "^0.1.13",
    "spt-rabbit-helpers": "^1.0.6",
    "tsyringe": "^4.3.0",
    "typeorm": "^0.2.25"
  },
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }
}

tsconfig:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "allowJs": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "strictPropertyInitialization": false,
    "moduleResolution": "node",
    "baseUrl": "./src",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "forceConsistentCasingInFileNames": true,
    "noImplicitAny": true,
    "typeRoots": ["node_modules/@types", "@types"]
  },
  "include": ["src", "__tests__"],
  "exclude": ["node_modules"]
}

main:

import 'reflect-metadata';
import express from 'express';
import { RabbitServer } from 'spt-rabbit-helpers';
import validateEnv from 'utils/validateEnvs';
import {
  RabbitMqConnectionFactory,
  ConsumerFactory,
  PublisherFactory,
  RabbitMqConnection,
} from 'nabbitmq';
import { container, singleton } from 'tsyringe';

const factory = new RabbitMqConnectionFactory();
factory.setUri('amqp://localhost:5672');
const ConsumerConnection = await factory.newConnection();
const PublisherConnection = await factory.newConnection();
container.registerInstance('Consumer_Connection', ConsumerConnection);
container.registerInstance('Publisher_Connection', PublisherConnection);
4 Answers

To run ts-node (or plain node for that matter) you need to use "module": "commonjs", "target": "ES2017", otherwise the import/export statements are illegally placed in an IIFE.

So I would suggest using another file called node.tsconfig.json with the following contents:

{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "target": "ES2017" // For NodeJS 8 compat, see https://www.typescriptlang.org/tsconfig#target for more info
    }
}

And then run ts-node with --project ./node.tsconfig.json

I had the same issue and I fixed it by changing the module in tsconfig.json to commonjs and removing the module key in package.json:

// tsconfig.json
{
    "module": "CommonJS",
}

If you are using React, "commonjs" can not be set for TypeScript.

tsconfig.json

{
    "compilerOptions": {
        "module": "esnext"
    }
}

package.json

{
    "type": "module",
    "scripts": {
        "tsnode": "node --loader ts-node/esm --no-warnings"
    },
    "dependencies": {
        "ts-node": "^10.4.0"
    }
}

hello.ts

import * as os from "os"
console.log("os", os);

Two ways to execute the TypeScript file:

  • node --loader ts-node/esm --no-warnings hello.ts
  • npm run tsnode hello.ts
Related