首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Node.js项目从普通ES6迁移到TypeScript

将Node.js项目从普通ES6迁移到TypeScript
EN

Stack Overflow用户
提问于 2019-01-10 21:49:08
回答 4查看 2.6K关注 0票数 8

开始将Node.js项目从普通ES6迁移到TypeScript。

我所做的:

代码语言:javascript
复制
npm install -g typescript
npm install @types/node --save-dev

设置tsconfig.json

代码语言:javascript
复制
{
     "compilerOptions": {
         "emitDecoratorMetadata": true,
         "experimentalDecorators": true,
         "moduleResolution": "node",
         "module": "commonjs",
         "target": "es6",
         "sourceMap": true,
         "outDir": "dist",
         "allowJs": true,
         "forceConsistentCasingInFileNames": true
     },
     "exclude": [
         "node_modules",
         "dist",
         "docs"
     ]
}

将所有文件扩展名从.js更改为.ts (node_modules除外):

代码语言:javascript
复制
find . -not \( -path node_modules -prune \) -iname "*.js" -exec bash -c 'mv "$1" "${1%.js}".ts' - '{}' \;

运行tsc现在会导致大量的错误,如下所示:

代码语言:javascript
复制
server.ts:13:7 - error TS2451: Cannot redeclare block-scoped variable 'async'.

13 const async = require('async');
     ~~~~~

或者这些:

代码语言:javascript
复制
bootstrap/index.ts:8:7
8 const async = require('async');
        ~~~~~
'async' was also declared here.

更新:

retry和其他npm包也是如此:

代码语言:javascript
复制
const retry = require('retry');

require语句更改为ES6 import语句主要解决了这些问题,但是必须一次迁移数千个文件是不可能的,所以我需要一种方法来坚持使用require。这个是可能的吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-01-13 13:31:02

这是与这一个相同的问题。

为了被视为ES模块,文件应该包含importexport语句,否则变量将被TypeScript编译器视为在全局范围内声明(即使在运行时不是这样)。

该解决方案与链接问题中的解决方案相同,即添加虚拟export {}。这可以通过regex替换成批完成,但是如果CommonJS、module.exports = ...导出已经在使用,它们之间可能会发生冲突。

使用CommonJS require()导入会导致非类型化代码。所有主要的库都已经按照@types/...或内置类型进行了分类。现有的NPM包可以与代码库中的regex匹配,以便批量安装相关的@types/...包,像const async = require('async')这样的导入可以用import async from 'async'批量替换。这需要设置esModuleInteropallowSyntheticDefaultImports选项。

票数 4
EN

Stack Overflow用户

发布于 2019-01-12 23:09:03

这是可能的,但你仍然需要编辑那些文件。

这两种方法都足够了。

  1. const ... = require()替换为import ... = require(): 导入异步=要求(‘异步’);.
  2. export {}添加到文件的顶部: 导出{};const异步=要求(‘异步’);.

初始问题的原因是,在TS中,不同的文件不是模块,除非它们显式声明为模块,因此它们在相同的全局范围内编译/执行,这就是为什么tsc报告不能重新声明async变量的原因。

来自文档

在TypeScript中,就像在ECMAScript 2015中一样,任何包含顶级importexport的文件都被视为模块。相反,没有任何顶级的import export export声明的文件被视为一个脚本,其内容在全局范围内可用(因此也适用于模块)。

票数 7
EN

Stack Overflow用户

发布于 2019-01-13 14:34:17

异步是一个受保护的关键字。当你使用异步/等待时,你可以跳过‘异步’包。如果您使用ES6+模块( ECMAScript made,ESM)正确地创建了,那么您还可以重命名所有文件-- *.mjs,例如index.mjs。如果您有文件名index.js,则通常假定它不是ESM。您必须向所有的ES6代码中添加类型/接口,因此根据您的情况,可能不可能一次性完成所有操作,这就是为什么我给出了ES2015+ ESM表示法中的示例。

对于TypeScript,您应该能够使用ESM,因为我想您需要更多最新的符号。为了在顶层使用异步,存在异步函数 index.mjs示例代码,包括从ES5/CommonJS *.js导入ES2015+和ESM导入/导出,最后是动态导入:

代码语言:javascript
复制
import { createRequireFromPath } from 'module'; // ESM import
import { fileURLToPath } from 'url';
const require = createRequireFromPath(fileURLToPath(import.meta.url));
// const untypedAsync = require('async');

class Index {

  constructor() {
    this._server = null;
    this.host = `localhost`;
    this.port = 8080;
  }

  set server(value) { this._server = value; }
  get server() { return this._server; }

  async start() {
    const http = await import(`http`); // dynamic import
    this.server = http.createServer(this.handleRequest);
    this.server.on(`error`, (err) => {
        console.error(`start error:`, err);
    });
    this.server.on(`clientError`, (err, socket) => {
        console.error(`start clientError:`, err);
        if (socket.writable) {
            return socket.end(`HTTP/1.1 400 Bad Request\r\n\r\n`);
        }
        socket.destroy();
    });
    this.server.on(`connection`, (socket) => {
      const arrival = new Date().toJSON();
      const ip = socket.remoteAddress;
      const port = socket.localPort;
      console.log(`Request from IP-Address ${ip} and source port ${port} at ${arrival}`);
    });
    this.server.listen(this.port, this.host, () => {
      console.log(`http server listening at ${this.host}:${this.port}`);
    });
  }

  handleRequest(req, res) {
    console.log(`url:`, req.url);
    res.setHeader(`Content-Type`, `application/json`);
    res.writeHead(200);
    res.end(JSON.stringify({ url: req.url }));
  }
}

export default Index; // ESM export
export const randomName = new Index(); // Usage: import { randomName } from './index.mjs';

async function main() {
  const index = new Index();
  const cjs = require(`./otherfile.js`); // ES5/CommonJS import
  console.log(`otherfile:`, cjs);
  // 'async' can be used by using: cjs.untypedAsync
  await index.start();
}

main();

// in otherfile.js
const untypedAsync = require('async');
const test = {
  url: "url test",
  title: "title test",
};
module.exports = { test, untypedAsync }; // ES5/CommonJS export.

然而,使用.mjs与类型记录目前存在一些问题。请查看仍未解决的相关类型记录问题:.mjs输入文件.mjs输出文件。您至少应该将您的.ts转到.mjs以解决您的问题。脚本看起来可能类似于(es6到ts源):

代码语言:javascript
复制
// in package.json
"files": [ "dist" ],
"main": "dist/index",
"types": "dist/index.d.ts",
"scripts": {
    "mjs": "tsc -d && mv dist/index.js dist/index.mjs",
    "cjs": "tsc -m commonjs",
    "start": "node --no-warnings --experimental-modules ./dist/index.mjs"
    "build": "npm run mjs && npm run cjs"
},
"devDependencies": {
    "typescript": "^3.2.2"
}

// in tsconfig.json
"compilerOptions": {
    "module": "es2015",
    "target": "ES2017",
    "rootDir": "src",
    "outDir": "dist",
    "sourceMap": false,
    "strict": true
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54137397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档