typescript tsc 编译js,运行报错:Error: *.default is not a constructor
时间:2024-2-3 21: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
文件中使用的一些关键属性的解释:
-
allowSyntheticDefaultImports
:- 用途: 允许 TypeScript 在没有明确指定默认导出的模块中合成默认导入。当您使用
import Aedes from 'aedes';
时,如果模块不提供默认导出,TypeScript 将尝试合成一个默认导入。 - 建议: 在使用模块系统的项目中,通常将其设置为
true
。
- 用途: 允许 TypeScript 在没有明确指定默认导出的模块中合成默认导入。当您使用
-
esModuleInterop
:- 用途: 启用 ECMAScript 模块的互操作性,允许直接导入默认导出的模块。
- 建议: 在使用模块系统的项目中,通常将其设置为
true
。
-
declaration
:- 用途: 生成与 TypeScript 文件对应的
.d.ts
声明文件。声明文件用于描述模块的类型信息,以便其他 TypeScript 项目可以正确地使用它。 - 建议: 在构建库或模块时,通常设置为
true
。
- 用途: 生成与 TypeScript 文件对应的
-
forceConsistentCasingInFileNames
:- 用途: 强制文件名大小写一致性。确保导入模块时文件名的大小写与实际文件名一致。
- 建议: 通常设置为
true
以防止由于大小写问题引起的潜在错误。
-
lib
:- 用途: 指定 TypeScript 编译器可以使用的库文件。
"DOM"
和"ES2022"
表示您的代码可能使用了浏览器 DOM API 和 ECMAScript 2022 的特性。 - 建议: 根据项目需求添加合适的库文件。
- 用途: 指定 TypeScript 编译器可以使用的库文件。
-
module
:- 用途: 指定生成的 JavaScript 代码使用的模块系统。
"ES2022"
表示使用 ECMAScript 2022 模块系统。 - 建议: 根据目标环境选择合适的模块系统。
- 用途: 指定生成的 JavaScript 代码使用的模块系统。
-
moduleResolution
:- 用途: 指定模块解析策略,
"node"
表示使用 Node.js 的解析策略。 - 建议: 在 Node.js 项目中通常将其设置为
"node"
。
- 用途: 指定模块解析策略,
-
rootDir
:- 用途: 指定源代码文件的根目录。用于确定编译器应该编译哪些文件。
- 建议: 设置为源代码文件的根目录。
-
sourceMap
:- 用途: 生成与 JavaScript 文件对应的 source map 文件,以便在调试时可以追踪到 TypeScript 代码。
- 建议: 在开发环境中通常设置为
true
。
-
strict
:- 用途: 启用 TypeScript 的严格模式,集成了多个严格的类型检查选项。
- 建议: 在项目中启用严格模式,以帮助捕获潜在的错误。
-
target
:- 用途: 指定生成的 JavaScript 代码的目标语言版本。
"ES2022"
表示生成的代码应符合 ECMAScript 2022 标准。 - 建议: 根据目标环境选择合适的语言版本。
- 用途: 指定生成的 JavaScript 代码的目标语言版本。
编译如何选择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。