Skip to content

搭配 Babel 和 Flow 使用

Flow 是 Facebook 开发的一款 JavaScript 静态类型检查器(static type checker)。它通过为 JavaScript 代码添加类型注解(type annotations),帮助在开发早期捕获错误。要在项目中使用 Flow 语法并使其能够在标准 JavaScript 环境中运行,你需要在构建过程中去除这些类型注解。Babel 正是实现这一目标的完美工具。

本章将指导你设置一个使用 Flow 进行类型检查(type checking),并使用 Babel 将 Flow 语法(以及其他现代 JavaScript 特性)转译(transpile)为可执行 JavaScript 的项目。我们将使用现代的 Babel(版本 7+)包。

创建一个新的项目目录并使用 npm 初始化:

mkdir babel-flow-project
cd babel-flow-project
npm init -y

你需要 Babel 的核心包、Babel CLI、Babel Flow 预设(preset)以及 Flow 本身(以 flow-bin 的形式):

npm install --save-dev @babel/core @babel/cli @babel/preset-flow flow-bin

如果你在使用 Flow 的同时还使用了其他现代 JavaScript 特性,可能还需要 @babel/preset-env:

npm install --save-dev @babel/preset-env

你的 package.json 文件中的 devDependencies 部分现在应该包含这些依赖项:

示例 package.json(devDependencies 部分):

"devDependencies": {
"@babel/cli": "^7.x.x",
"@babel/core": "^7.x.x",
"@babel/preset-env": "^7.x.x", // Optional, for other ES features
"@babel/preset-flow": "^7.x.x",
"flow-bin": "^0.x.x"
// Exact versions will vary
}

在项目根目录创建一个 babel.config.json 文件。这会告诉 Babel 使用 @babel/preset-flow 来去除 Flow 类型注解。如果你也使用了 @babel/preset-env,也将其包含在内。预设的应用顺序是反向的(最后一个先应用)。

babel.config.json:

{
"presets": [
"@babel/preset-env", // Optional, for other ES features
"@babel/preset-flow"
]
}

如果你只需要去除 Flow 类型并且不使用其他需要转译的 ESNext 特性,可以省略 @babel/preset-env。

在项目中初始化 Flow。这将创建一个 .flowconfig 文件。

npx flow init

默认的 .flowconfig 通常足以开始使用。

在你的 package.json 文件中添加用于运行 Flow 和使用 Babel 构建代码的脚本:

"scripts": {
"flow": "flow",
"build": "babel src -d dist",
"start": "node dist/main.js" // Example: if your entry point is main.js
}

创建一个 src 目录,并在其中添加一个使用 Flow 语法的 JavaScript 文件。例如,src/main.js:

src/main.js:

// @flow
function greet(name: string): string {
return `Hello, ${name}!`;
}
let user: string = "Alice";
console.log(greet(user));
// Example of a type error Flow would catch:
// console.log(greet(123)); // Error: number is incompatible with string

文件顶部的 // @flow 注释告诉 Flow 检查此文件。

运行 Flow 类型检查器:

npm run flow

如果没有类型错误,Flow 将报告 “No errors!”。如果你取消注释 console.log(greet(123)); 这一行,Flow 将报告一个类型错误。

现在,使用 Babel 脚本转译你的代码。这将去除 Flow 类型注解。

npm run build

这个命令将创建一个 dist 目录,其中包含 main.js。Flow 类型注解(: string)将被移除。

dist/main.js(经过 Babel 转译后):

// @flow // This comment might also be stripped by some configurations, or kept.
// Babel primarily removes type annotations.
function greet(name) {
return "Hello, ".concat(name, "!");
}
var user = "Alice";
console.log(greet(user)); // console.log(greet(123));

注意:如果你也使用了 @babel/preset-env 并针对较旧的环境,其他转换(例如,如果目标环境是非常老的 JS,模板字面量会转换为 concat)也会发生。

现在你可以运行转译后的 JavaScript 代码了,它是没有 Flow 类型的纯 JavaScript:

npm start

这将输出:

Hello, Alice!

为何使用 Flow 与 Babel 结合?

  • 早期错误检测:Flow 在开发期间捕获类型错误,而非运行时。
  • 提高代码质量:类型注解使代码更易于理解和维护。
  • 渐进式采用:Flow 可以逐步引入到现有的 JavaScript 项目中。
  • 兼容性:Babel 通过去除类型,确保带有 Flow 注解的代码可以在任何 JavaScript 环境中运行。

替代方案:TypeScript 是另一种流行的为 JavaScript 添加静态类型的选择。它有自己的编译器(tsc),但也可以通过 @babel/preset-typescript 与 Babel 集成。选择 Flow 还是 TypeScript 通常取决于项目需求和团队偏好。

这个设置演示了 Babel 如何通过处理必要的转换来实现 Flow 等高级 JavaScript 工具的使用,从而确保兼容性。