如何将 ts 集成到 node 项目中

为什么使用 TypeScript?

TypeScript 为 JavaScript 提供了可选的静态类型。静态类型的主要好处是在构建时检查和发现类型错误,所以代码部署到生产环境后运行更稳定。

环境准备

Node 版本 >= 16

初始化项目

mkdir node-ts
cd node-ts
npm init -y

安装 typescript

npm i typescript -D

初始化 ts 配置文件

npx tsc --init

安装 @tsconfig/node16

npm i @tsconfig/node16 -D

@tsconfig/node16 为 TypeScript 团队为 Node.js v16 提供的基本配置。

tsconfig.json 中增加一下配置

{
  "extends": "@tsconfig/node16/tsconfig.json",
  "include": ["src"],
  "exclude": ["node_modules"]
}

编写 ts 文件

src 下新建 index.ts 文件

const bar = 'bar'

console.log(bar)

通过 npx tsc 运行。js 文件是编译出来了,但是控制台报出错误:

TS2584: Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.

发生此错误是因为在 tsconfig.json 配置文件和 @tsconfig/node16 的配置中 compilerOptions 没有设置 lib 选项。该选项包含对象的类型定义和其他特定于浏览器的 API。将 "dom", "ESNext" 添加到 lib 中解决。但这不是 Node.js 项目的正确解决方案。正确的方式是安装 Node API 的类型定义,使 TypeScript 编译器可以理解和验证所有内置的 Node.js API。

安装 @types/node

npm i @types/node -D

安装完成后再次运行 npx tsc 错误消失。

如果要更改 js 文件的输出位置,可以在文件中 tsconfig.json 中指定 outDir 选项,编译后 js 文件将输出到 dist 目录下。

创建一个 http 服务感受下 ts 的类型检查和提示:

// index.ts
import http from 'http'

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('hello ts node!')
})

server.listen(3000, () => {
  console.log('runing...')
})

因为 node 运行时不能直接 ts 文件,所以需要将 ts 文件编译成 js 执行。运行 npx tsc 然后 node dist/index.js,就可以访问 http://localhost:3000/了。

这种方式每次改动代码都要编译,然后执行 js 文件。

可以通过 tsc -w 监听文件的变化,然后使用nodemon工具监听js文件的变化。有点繁琐。

使用 ts-node 直接执行 ts 文件

通过 ts-node CLI 在直接执行 ts 文件。安装 ts-node

npm i ts-node -D

执行 npx ts-node src/index.ts,完全可行。

ts-node 作为 ts 源码 和 node 运行时之间的中间者。在执行生成的 js 代码之前转译源代码。这种执行速度更快。

另外 ts-node 启用的功能是将现代 esm 语法转换为 CommonJS 语法。这意味着在使用时 ts-node,您可以在代码中通 import 而不是 require 使用 node 模块。

package.json 中新增脚本:

{
  "scripts": {
    "dev": "ts-node src/index.ts"
  }
}

使用 tsc-node-dev 可以监听文件的变化,当文件内容变化后重新编译并运行。

{
  "scripts": {
    "dev": "ts-node-dev src/index.ts"
  }
}

ts 与第三方 npm 集成

当使用 npm 上的 node 模块时,可能需要额外的配置才能编译项目。

因为我们遇到的大多数模块都是用 js 编写的,因此 ts 无法确定方法的类型。模块中的所有内容都隐式为 any。

以 express 为例:

安装 express

npm i express
import express from 'express'

const app = express()

app.get('/', function (req, res) {
  res.send('Hello World')
})

app.listen(3000)

会抛出错误: 无法找到模块“express”的声明文件,而且由于 tsconfig.json 的 strict 选项为 true,因此也启用了 noImplicitAny 编译器选项。使得 ts 在无法确定值的类型时会报错而不是进行推断类型。 所以 req 和 res 报错。

可以为模块提供类型声明文件来修复此错误。DefinitiveTyped GitHub 上提供了许多流行的 npm 包的类型定义。通过 @types 作用域安装包的类型定义。安装 express 的类型定义文件:

npm install @types/express -D

再次运行 npx ts-node src/index.ts 就成功了。

这种方式无法实时监听文件的变化,可以使用 nodemon,通过 tsc -w 监听 ts 文件,变化后重新编译成 js,nodemon 监听到 js 变化后重新执行 js。

使用 ESLint 对 ts 进行检查

安装 ESLint

npm i eslint -D

要 eslint 对 ts 的检验,需要 eslint 的 ts 插件,@typescript-eslint/parser @typescript-eslint/eslint-plugin

npm i @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

根目录创建 .eslintrc.js 配置文件,配置内容为:

module.exports = {
  env: {
    node: true,
    es2021: true
  },
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['@typescript-eslint']
}

package.json 中添加 lint 脚本:

{
  "scripts": {
    "lint": "eslint . --fix"
  }
}

代码中新增:

let bar = 'bar'

console.log(bar)

执行 npm run lint,let 改成 const,eslint 生效。

为了防止 ESLint dist 下的 js 文件检查,创建 .eslintignore 文件,并将 dist 添加进去。因为 node_modules 文件夹中的所有内容以及以点字符开头的文件或文件夹(eslint 配置文件除外)都会被自动忽略,因此无需在 .eslintignore 文件中设置。

部署到生产环境

虽然 ts-node 在生产环境中使用也是是安全的。但为了减少服务器的启动时间以及减少额外的内存使用,最好预先编译源文件。将编译后的 js 部署到生产环境。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容