资讯专栏INFORMATION COLUMN

前端进阶(5) - js 扩展:静态类型检查(facebook flow)

孙淑建 / 651人阅读

摘要:扩展静态类型检查语言与系列等语言有一点很大的不同,就是语言是弱类型语言。但其实很多开发人员还是比较喜欢用来开发项目,所以开发出来帮助语言扩展静态类型检查功能,规避上面提到的问题。

js 扩展:静态类型检查(facebook flow)

js 语言与 java、C 系列等语言有一点很大的不同,就是 js 语言是弱类型语言。js 语言的这个特性可能让大家觉得 js 很自由,没有强制性的约束,但是当遇到大型项目的时候,js 的这个特性就会变得比较麻烦,因为这会导致团队的代码很不可控。这个原因也是促使 TypeScript 诞生的一个很重要的原因。

但其实很多开发人员还是比较喜欢用 js 来开发项目,所以 facebook 开发出 flow 来帮助 js 语言扩展静态类型检查功能,规避上面提到的问题。

1. 代码示例

flow 规定,在需要做 "flow 静态类型检查" 文件的开头加上 // @flow 这段注释,让工具识别这个文件需要做静态类型检查,否则就会当作一般 js 文件对待,不做静态类型检查。

flow 静态类型几乎可以应用到所有的 js 对象,包括 es6 扩展的 class, module 等,也包括 jsx 语法。

以下是一些基础的静态类型举例,更详细的可以查看 Type Annotations | Flow.

1.1 基本类型

与 js 的基本数据类型类似,包括:

boolean: 对应 js 的 Boolean 类型

number: 对应 js 的 Number 类型

string: 对应 js 的 String 类型

null: 对应 js 的 null

void: 对应 js 的 undefined

正常的 js 代码

let hello = "hello"; // 声明一个变量

hello = 2 * 2; // 重新赋值

hello = []; // 重新赋值

加上 flow 静态类型检查扩展的代码

// @flow

let hello: string = "hello"; // 声明一个 string 类型的变量

hello = 2 * 2; // 报错

hello = []; // 报错

hello = "hi"; // 重新赋值
1.2 函数

正常的 js 代码

function plus(a, b) {
  return a + b;
}

plus(); // NaN
plus(1); // NaN
plus(1, 2); // 3
plus("hello"); // "helloundefined"
plus("hello", " hi"); // "hello hi"
plus({}, {}); // "[object Object][object Object]"

加上 flow 静态类型检查扩展的代码

// @flow

// 定义一个 "两个数字参数,返回值也是数字" 的函数
function plus(a: number, b: number): number {
  return a + b;
}

plus(); // 报错
plus(1); // 报错
plus("hello"); // 报错
plus("hello", " hi"); // 报错
plus({}, {}); // 报错

plus(1, 2); // 3
1.3 可能(Maybe),可选(Optional),语义(Literal),混合(Mixed)

可能(Maybe)类型用一个 ? 在类型前面表示,包含类型本身、nullundefined

// @flow

let hello: ?string; // 声明一个数据类型可以是 string, null, undefined 的变量

hello = null; // 赋值
hello = undefined; // 重新赋值
hello = "hello"; // 重新赋值
hello = 1; // 报错
hello = true; // 报错

可选(Optional)类型一般用于对象属性或者函数参数,在名称后面加一个 ?,包含类型本身、undefined

// @flow

const obj: {hello? : string}; // 属性 hello 可以是 string, undefined

obj = {}; // 赋值
obj = {hello: undefined}; // 重新赋值
obj = {hello: "hello"}; // 重新赋值
obj = {hello: null}; // 报错
obj = {hello: 1}; // 报错
obj = {hello: true}; // 报错

// 属性 param 可以是 number, undefined
function method(param?: number) { /* ... */ }

method(); // 正常
method(undefined); // 正常
method(1.12); // 正常
method(null); // 报错
method("hello"); // 报错

语义(Literal)类型一般用于声明某个,某几个特定的值(多个值用 | 分隔)

// @flow

let hello: "hello"; // 声明一个只能赋值 "hello" 的变量

hello = "hello"; // 赋值
hello = "hi"; // 报错
hello = 12; // 报错
hello = undefined; // 报错
hello = null; // 报错

function method(param: 1 | "hi" | boolean): void { /* ... */ }

method(); // 报错,缺少参数
method(1); // ok
method(1.2); // 报错,类型不对
method("hi"); // ok
method("hello"); // 报错,类型不对
method(true); // ok
method(false); // ok

混合(Mixed)类型是指任意数据类型

// @flow

let hello: mixed; // 声明一个 mixed 类型的变量

hello = "hello"; // 赋值
hello = "hi"; // 重新赋值
hello = 12; // 重新赋值
hello = undefined; // 重新赋值
hello = null; // 重新赋值
1.4 复合类型

数组

// @flow

let arr1: Array = [true, false, true]; // 声明一个元素是 boolean 的数组
arr1 = [true, 1]; // 报错,1 不是 boolean 值
arr1 = [""]; // 报错,"" 不是 boolean 值

let arr2: Array = ["A", "B", "C"]; // 声明一个元素是 string 的数组

let arr3: Array = [1, true, "three"] // 声明一个元素是任意类型的数组
arr1 = [true, 1]; // 重新赋值 
arr1 = [""]; // 重新赋值

map

// @flow

// 声明一个 map 类型,其有一个名为 foo,类型 boolean 的子元素
let obj1: { foo: boolean } = { foo: true };
obj1 = {}; // 报错,缺少 foo 这个属性值
obj1 = {foo: 1}; // 报错,属性值 foo 的类型必须是 boolean
obj1 = {foo: false, bar: "hello"}; // 重新赋值

// 声明一个 map 类型,其有名为 foo, bar, baz,类型 number, boolean, string 的子元素
let obj2: {
  foo: number,
  bar: boolean,
  baz: string,
} = {
  foo: 1,
  bar: true,
  baz: "three",
};

更静态类型可以查看 Type Annotations | Flow.

2. 使用工具

安装

# 全局安装
npm i -g flow-bin

# 本地安装
npm i -D flow-bin

使用

flow init                       # 初始化项目

flow check path/to/dir          # 检查这个目录下所有的文件
flow check path/to/js/file      # 检查指定文件
3. 配合 babel 一起使用

因为 flow 静态类型只是对 js 的扩展,并不是 js 原生支持的,也不能直接运行,所以,一般 flow 都是配合 babel 一起使用的,这样就可以在程序运行的时候进行静态类型检查,达到我们想要的效果。

3.1 babel-preset-flow

安装 babel-preset-flow,这样 babel 在转码 js 文件时就能识别 flow 的语法。

npm i -D babel-preset-flow

.babelrc

{
  "presets": ["flow"]
}

源文件(flow)

// @flow

// 定义一个 "两个数字参数,返回值也是数字" 的函数
function plus(a: number, b: number): number {
  return a + b;
}

plus(); // 报错
plus(1); // 报错
plus("hello"); // 报错
plus("hello", " hi"); // 报错
plus({}, {}); // 报错

plus(1, 2); // 3

转码后的文件

// 定义一个 "两个数字参数,返回值也是数字" 的函数
function plus(a, b) {
  return a + b;
}

plus(); // 报错
plus(1); // 报错
plus("hello"); // 报错
plus("hello", " hi"); // 报错
plus({}, {}); // 报错

plus(1, 2); // 3
3.2 babel-plugin-flow-runtime

一般会在开发环境下,使用 babel-plugin-flow-runtime 插件,这样就可以在开发的时候,实时检查数据类型,就像原生的运行 flow 静态类型检查一样。(一般在产品环境不会使用这个功能,因为会额外消耗 js 的性能)

npm i -D babel-plugin-flow-runtime flow-runtime

.babelrc

{
  "presets": ["flow"],
  "plugins": ["flow-runtime"]
}

源文件(flow)

// @flow

// 定义一个 "两个数字参数,返回值也是数字" 的函数
function plus(a: number, b: number): number {
  return a + b;
}

plus(); // 报错
plus(1); // 报错
plus("hello"); // 报错
plus("hello", " hi"); // 报错
plus({}, {}); // 报错

plus(1, 2); // 3

转码后的文件

import t from "flow-runtime";


// 定义一个 "两个数字参数,返回值也是数字" 的函数
function plus(a, b) {
  return a + b;
}

t.annotate(plus, t.function(t.param("a", t.number()), t.param("b", t.number()), t.return(t.number())));
plus(); // 报错
plus(1); // 报错
plus("hello"); // 报错
plus("hello", " hi"); // 报错
plus({}, {}); // 报错

plus(1, 2); // 3

这个时候,js 文件就会导入 flow-runtime 模块,对 plus 函数的参数 a, b 和返回值进行数据类型检查,如果不符合数据定义,就会报错。

4. 后续

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96960.html

相关文章

  • Flow, 一个新的Javascript静态类型检查

    摘要:原文链接翻译于今天我们兴奋的发布了的尝鲜版,一个新的静态类型检查器。为添加了静态类型检查,以提高开发效率和代码质量。这最终形成一个高度并行增量式的检查架构,类似。知道缩小类型范围时做动态检查的影响。 原文链接:https://code.facebook.com/posts/1505962329687926/flow-a-new-static-type-checker-for-java...

    liangzai_cool 评论0 收藏0
  • JS 静态类型检查工具 Flow

    摘要:本文主要介绍了解决作为弱类型语言没有类型检查痛点的静态类型检查工具,并且介绍了在中使用的方法,最后介绍了一些常用的语法。 本文主要介绍了解决JS作为弱类型语言没有类型检查痛点的静态类型检查工具 Flow ,并且介绍了在WebStorm中使用Flow的方法,最后介绍了一些常用的Flow语法。 1. 简介 JS作为一种脚本语言是没有类型检测的,这个特点有时候用着很方便,但在一个较大的项目中...

    CloudDeveloper 评论0 收藏0
  • 两年React老兵的总结 - 类型检查

    摘要:系列引言最近准备培训新人为了方便新人较快入手开发并编写高质量的组件代码我根据自己的实践经验对组件设计的相关实践和规范整理了一些文档将部分章节分享了出来由于经验有限文章可能会有某些错误希望大家指出互相交流由于篇幅太长所以拆分为几篇文章主要有以 系列引言 最近准备培训新人, 为了方便新人较快入手 React 开发并编写高质量的组件代码, 我根据自己的实践经验对React 组件设计的相关实践...

    scola666 评论0 收藏0
  • (译 & 转载) 2016 JavaScript 后起之秀

    摘要:在年成为最大赢家,赢得了实现的风暴之战。和他的竞争者位列第二没有前端开发者可以忽视和它的生态系统。他的杀手级特性是探测功能,通过检查任何用户的功能,以直观的方式让开发人员检查所有端点。 2016 JavaScript 后起之秀 本文转载自:众成翻译译者:zxhycxq链接:http://www.zcfy.cc/article/2410原文:https://risingstars2016...

    darry 评论0 收藏0
  • flow从零开始----安装和配置

    摘要:资源官网安装参考什么是是一个弱类型的解释性语言,无法在编译环节进行静态类型校验,如果想也具备静态类型检查功能。那就得使用到由推出,官网是。 资源 官网:https://flow.org/ 安装:https://flow.org/en/docs/inst... 参考:https://www.01hai.com/note/av... https://www.jianshu.com/p...

    KoreyLee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<