«

typescript tsc 编译js,运行报错:Error: *.default is not a constructor

时间:2024-2-3 10:59     作者:wanzi     分类:


错误

错误1

var aedes = new aedes_1.default();
^

TypeError: aedes_1.default is not a constructor

错误2

Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use node --trace-warnings ... to show where the warning was created)
/Users/jiechengyang/src/node-app/mqtt-examples/dist/01/mqtt-server.js:1
import Aedes from 'aedes';
^^^^^^

SyntaxError: Cannot use import statement outside a module

源码分析

需要编译的ts:mqtt_server.js

import Aedes from 'aedes'
import { createServer } from 'net'

const port = 1883

const aedes = new Aedes()
const server = createServer(aedes.handle)

server.listen(port, function () {
  console.log('server started and listening on port ', port)
})

aedes.d.ts 源码

import Aedes, { AedesOptions } from './types/instance'

export declare function createBroker(options?: AedesOptions): Aedes

export * from './types/instance'
export * from './types/packet'
export * from './types/client'

export { default } from './types/instance'

tsconfig.json配置:

{
    "compilerOptions": {
      "target": "es6",
      "module": "commonjs",
      "esModuleInterop": true,
      "strict": true
    },
    "include": ["src/**/*.ts"],
    "exclude": ["node_modules"]
  }

编译的结果:

{
    "compilerOptions": {
      "target": "es6",
      "module": "commonjs",
      "esModuleInterop": true,
      "strict": true
    },
    "include": ["src/**/*.ts"],
    "exclude": ["node_modules"]
  }

问题解读

错误1

因为是初学ts,造成上面的问题的原因是:个人使用的编译选项不对导致,因此,应该熟悉tsconfig.json 的编译参数.最后的tsconfig.json配置如下:

 {
    "compilerOptions": {
      "allowSyntheticDefaultImports": true,
      "declaration": true,
      "esModuleInterop": true,
      "forceConsistentCasingInFileNames": true,
      "lib": [
        "DOM",
        "ES2022"
      ],
      "module": "ES2022",
      "moduleResolution":"node",
    //   "outDir": "dist",
      "rootDir": "src",
      "sourceMap": true,
      "strict": true,
      "target": "ES2022"
    },
    "include": [
      "src/**/*.ts"
    ]
  }  

错误2

报错信息表明您的 JavaScript 文件被 Node.js 解释为 ECMAScript 模块(ES module),而不是 CommonJS 模块。这通常是因为文件扩展名是 .mjs,或者因为 type: module 被设置在了 package.json 文件中。

在您的情况下,看起来您正在使用 import 语句导入模块,这是 ECMAScript 模块的语法。然而,默认情况下,Node.js 将文件当作 CommonJS 模块处理。

为了解决这个问题,有几个选项:

将文件扩展名更改为 .mjs:

将您的文件扩展名从 .js 更改为 .mjs。这会告诉 Node.js 将文件视为 ECMAScript 模块。
将 type 设置为 module:

在您的 package.json 文件中,可以添加 "type": "module",以将所有 .js 文件视为 ECMAScript 模块。

{
  "type": "module",
  "scripts": {
    "start": "node your-script.js"
  }
}

注意:将 "type": "module" 添加到 package.json 可能会影响到项目中其他依赖的模块。这是因为 CommonJS 和 ECMAScript 模块有一些不同之处。确保您的项目及其依赖项对 ECMAScript 模块提供了正确的支持。

tsconfig配置参数说明

当配置 TypeScript 编译器选项时,各个属性有着不同的作用。以下是您 tsconfig.json 文件中使用的一些关键属性的解释:

  1. allowSyntheticDefaultImports:

    • 用途: 允许 TypeScript 在没有明确指定默认导出的模块中合成默认导入。当您使用 import Aedes from 'aedes'; 时,如果模块不提供默认导出,TypeScript 将尝试合成一个默认导入。
    • 建议: 在使用模块系统的项目中,通常将其设置为 true
  2. esModuleInterop:

    • 用途: 启用 ECMAScript 模块的互操作性,允许直接导入默认导出的模块。
    • 建议: 在使用模块系统的项目中,通常将其设置为 true
  3. declaration:

    • 用途: 生成与 TypeScript 文件对应的 .d.ts 声明文件。声明文件用于描述模块的类型信息,以便其他 TypeScript 项目可以正确地使用它。
    • 建议: 在构建库或模块时,通常设置为 true
  4. forceConsistentCasingInFileNames:

    • 用途: 强制文件名大小写一致性。确保导入模块时文件名的大小写与实际文件名一致。
    • 建议: 通常设置为 true 以防止由于大小写问题引起的潜在错误。
  5. lib:

    • 用途: 指定 TypeScript 编译器可以使用的库文件。"DOM""ES2022" 表示您的代码可能使用了浏览器 DOM API 和 ECMAScript 2022 的特性。
    • 建议: 根据项目需求添加合适的库文件。
  6. module:

    • 用途: 指定生成的 JavaScript 代码使用的模块系统。"ES2022" 表示使用 ECMAScript 2022 模块系统。
    • 建议: 根据目标环境选择合适的模块系统。
  7. moduleResolution:

    • 用途: 指定模块解析策略,"node" 表示使用 Node.js 的解析策略。
    • 建议: 在 Node.js 项目中通常将其设置为 "node"
  8. rootDir:

    • 用途: 指定源代码文件的根目录。用于确定编译器应该编译哪些文件。
    • 建议: 设置为源代码文件的根目录。
  9. sourceMap:

    • 用途: 生成与 JavaScript 文件对应的 source map 文件,以便在调试时可以追踪到 TypeScript 代码。
    • 建议: 在开发环境中通常设置为 true
  10. strict:

    • 用途: 启用 TypeScript 的严格模式,集成了多个严格的类型检查选项。
    • 建议: 在项目中启用严格模式,以帮助捕获潜在的错误。
  11. target:

    • 用途: 指定生成的 JavaScript 代码的目标语言版本。"ES2022" 表示生成的代码应符合 ECMAScript 2022 标准。
    • 建议: 根据目标环境选择合适的语言版本。

编译如何选择commonjs 和ecmascript

选择使用 CommonJS 还是 ECMAScript 模块(ES module)通常取决于您的项目的特定要求和部署环境。下面是一些建议:

使用 CommonJS:
Node.js 项目: 如果您的项目是一个 Node.js 项目,特别是在旧版 Node.js 中,使用 CommonJS 是很自然的选择。Node.js 长期以来一直使用 CommonJS 模块系统。

现有项目: 如果您的项目中已经使用了 CommonJS,为了保持一致性,可能更容易继续使用 CommonJS。

npm 生态系统: 大多数 Node.js 包都是以 CommonJS 格式发布的,因此在使用 npm 生态系统中,使用 CommonJS 通常更为方便。

使用 ECMAScript 模块:
前端项目: 在浏览器环境或支持 ES module 的环境中,可以考虑使用 ECMAScript 模块。现代前端开发中,许多工具和框架都支持 ES module。

静态分析和优化: ECMAScript 模块在静态分析和优化方面具有一些优势,因为它们提供了更多的信息,这有助于一些工具进行更好的代码优化。

模块化加载器: 如果您的项目中使用了模块加载器(如Webpack、Rollup等),这些工具通常支持 ES module,并且可以更好地进行代码分割和懒加载等优化。

组合使用:
在某些场景下,您也可以在同一项目中同时使用 CommonJS 和 ES module,这种混合使用的方式在过渡期或特定的工作流中可能会有用。例如,在一些前端项目中,可以使用 Babel 或 Webpack 进行模块的转换,将 CommonJS 转换为 ES module 以获得一些优势。

总体而言,选择 CommonJS 还是 ES module 取决于您项目的具体需求、使用的环境以及团队的偏好。在许多情况下,Node.js 项目会继续使用 CommonJS,而前端项目则更倾向于使用 ES module。