Node.js + TypeScript:类型脚本编译代码的语法不明确
Posted
技术标签:
【中文标题】Node.js + TypeScript:类型脚本编译代码的语法不明确【英文标题】:Node.js + TypeScript: Unclear syntax with type script compiled code 【发布时间】:2016-04-03 21:11:17 【问题描述】:我正在尝试在我的节点项目中使用 TypeScript,但我遇到了一些问题。
这是我的 index.ts 文件:
import express from 'express';
const app = express();
我在跑步:
tsc --module commonsjs -d index.ts
我的输出是 index.js:
var express_1 = require('express');
var app = express_1["default"]();
这个["default"]
是从哪里来的?它使我的代码无法正常运行:
var app = express_1["default"]();
^
TypeError: express_1.default is not a function
据我了解,我应该得到没有“默认”括号的代码,并且它会正常工作 - 我尝试删除括号并且它有效。
我在这里错过了什么?
【问题讨论】:
模块应该是commonjs
而不是commonsjs
。这可能会给您带来问题。
考虑使用 esModuleInterop: true 编译器选项(在您的 tsconfig 中设置)。这使您可以按照您的预期执行import express from 'express'
你也可以试试import * as express from 'express'
,而不是import express from 'express'
- 哪个工作通常取决于tsconfig.json中的esModuleInterop设置
【参考方案1】:
最安全的解决方案是:
import express = require('express');
这转换为:
var express = require('express');
import require 声明的官方文档可以在here找到。
从最后一段 here 来看,我相信 TypeScript 期望一个名为“default”的导出作为您上面的代码运行。
旁注:看起来 TypeScript 的最新版本(在撰写本文时为 typescript@1.8.0-dev.20151229)会在尝试使用缺失默认值的编译尝试时抛出警告:
index.ts(1,8): error TS1192: Module '"express"' has no default export.
旁注 2:可以在 here 找到 Microsoft 使用 import * as express from 'express';
语法的示例。当针对 commonjs
的模块(在本例中为 they are)时,这也将转换为 var express = require('express');
。
如果您至少有 TypeScript 2.7 并且以 CommonJS 为目标,您也可以使用 esModuleInterop。
来自链接:
为了给用户提供与 Babel 或 Webpack 相同的运行时行为,TypeScript 在发射到遗留模块格式时提供了一个新的 --esModuleInterop 标志。
在新的 --esModuleInterop 标志下,这些可调用的 CommonJS 模块必须作为默认导入导入,如下所示:
import express from "express";
let app = express();
我们强烈建议 Node.js 用户将此标志与 CommonJS 的模块目标一起用于 Express.js 等库,这些库导出可调用/可构造的模块。
【讨论】:
import *
是导入遗留模块的错误方法。见***.com/a/29598404/252087。
考虑使用 esModuleInterop: true 编译器选项(在您的 tsconfig 中设置)。这使您可以按照您的预期执行import express from 'express'
【参考方案2】:
我通过将以下内容添加到 tsconfig.json
解决了这个问题:
"compilerOptions":
...
"module": "commonjs",
"esModuleInterop": true,
...
esModuleInterop 标志被描述为:“发出 __importStar 和 __importDefault 帮助程序以实现运行时 babel 生态系统的兼容性,并启用 --allowSyntheticDefaultImports 以实现类型系统的兼容性。”
https://www.typescriptlang.org/docs/handbook/compiler-options.html
【讨论】:
这解决了我的问题!可能知道 ts-node-dev 正在使用 TypeScript 的配置,所以我添加了一个tsconfig.json
文件。谢谢!
这应该是公认的答案,因为它允许简单地使用import express from 'express'
我同意这是较新版本的打字稿的正确策略。直到 2018 年发布的 typescript 2.7 才提供此选项。【参考方案3】:
如果您尝试使用 Express.js 等非 ES6 模块的默认导出,则需要使用旧版导入语法 import express = require('express')
。
在 ES6 模块中,没有像 Node.js 模块的 module.exports
或 AMD 模块的 return
那样的默认值导出; ES6 模块的默认导出只是 default
键。这就是为什么当您尝试使用 ES6 默认 import
时,TypeScript 会生成 javascript 以访问 default
属性。
更多信息请访问New es6 syntax for importing commonjs / amd modules i.e. `import foo = require('foo')`。
【讨论】:
谢谢!多亏了你,我对这个主题进行了一些研究。 我不明白您为什么接受另一个答案作为正确答案。这是错误的答案。 如果当前版本的 Typescript 确实是错误的答案,那么我建议你让微软编辑他们的示例。 @dvlsg Microsoft 的示例与 OP 正在执行的操作不相同!该示例仅使用来自express
的static
属性,它不 尝试使用默认导出(因为它不能,因为它是错误的并且不起作用)。在这种情况下,import *
很好,因为它使导入的express
标识符成为一个空白列表,然后根据 ES 规范将 express 模块的所有导出属性添加到该列表中。使用默认导出不正确。
据我所知,原始问题中的 const app = express();
正是 Microsoft example 中所做的事情(当然,减去 const)。我同意require
将在更多情况下工作,但我会相应地进行编辑。【参考方案4】:
如果您仍想使用 import
关键字,请按如下方式使用:
import express from "express";
// If the above is not supported by your project environment then follow as below
import * as express from "express";
在文件tsconfig.json
"compilerOptions":
...
"module": "commonjs"
...
感谢Josh Dando。
【讨论】:
确保你的 tsconfig.json 中有 "module": "commonJS"【参考方案5】:另一个可能适合您的解决方案是这样做:
import * as express from express;
const app = express();
它应该以相同的方式工作。
【讨论】:
以上是关于Node.js + TypeScript:类型脚本编译代码的语法不明确的主要内容,如果未能解决你的问题,请参考以下文章
nodemon 没有在 webpack-typescript-node.js 中监视目录?