Flow之一个新的Javascript静态类型检查器


Posted in Javascript onDecember 21, 2015

今天我们兴奋的发布了 Flow 的尝鲜版,一个新的Javascript静态类型检查器。Flow为Javascript添加了静态类型检查,以提高开发效率和代码质量。更明确的说,静态类型检查提供的好处像早期错误检查,帮助你发现一些只有在运行时才能发现的错误,以及代码智能感知,它会帮助代码维护,查找,重构和优化。

Flow之一个新的Javascript静态类型检查器

我们设计Flow的所有功能构建在现有Javascript规范之上。因为Flow主动地在后台工作,所以额外的编译开销很小。Flow并不要求开发者如何编写代码 —— 她用一套复杂的算法分析你熟悉的代码风格。

Flow仍然在初期阶段,但是我们已经在Facebook使用了。我们希望你在自己的项目中愉快的使用,期待你的反馈。可以访问 flowtype.org 快速开始。

总览

Facebook超爱Javascript;它快,表达性好,而且到处运行,是构建产品的极佳语言。同时,因为没有静态类型让开发者困扰。Bug难以发现(比如,崩溃的原因隐藏很深),代码维护犹如噩梦(比如,在不知道所有依赖的情况下进行重构风险很大)。Flow改进了速度和效率促进了开发者在使用Javascript的生成效率。

在Javascript之上添加一层静态系统并不简单。Javascript的积木(building block)表现力极高,一个简单的类型系统并不能精确组合出应有的语义。为了支持不同的Javascript编程范式和习惯,Flow引入了类似数据流(data-flow)和控制流(control-flow)这类通常用于编译时提取语义的分析技术。然后用提取的信息,加上先进的类型原理来做类型推断。当然,仅有一个强力的静态类型分析还不够 —— Javascript代码库会很大,这要求类型检查必须闪电般快速,才能不打断开发者编辑-运行的流程。Flow按模块执行分析,所有的类型都限制在模块边界以内。这最终形成一个高度并行、增量式的检查架构,类似 Hack 。这使得类型检查响应快速,即使是百万行级别代码。

Flow的类型检查是选择性的 —— 你不需要一次性执行检查所有。然而,Flow背后的设计基于假定大多数Javascript的代码类型是隐式静态类型;虽然类型可能不会到处在代码中出现,它们是以一种可以按照代码正确性推理出来的形式存在于开发者的思路中。一旦可能,Flow就去推断这些类型,意味着它可以不需要改动代码就能发现类型错误。另一发面,一些如存在于框架中的Javascript代码,大量使用了反射使得静态类型推断非常困难。对于这种天然动态的代码,类型检查就会错漏百出,因此Flow提供对此类代码添加信任并继续。这种设计在Facebook内部被大量的Javascript代码库所验证:大多数代码没有通过隐式静态类型检查条目,这些条目让开发者可以不用添加注释就能检查代码类型错误。

这使得Flow从根本上区别于其他Javascript的类型系统(如TypeScript),通过弱化的假设大多数JavaScript代码是动态输入的,并由开发者自己表达哪些代码应该是静态类型。通常来看,这类设计会导致检查覆盖率降低:更少的类型错误被检测到,工具不够高效。然而对于某些情况下是合理的,一般这种设计如果没有通过大量额外的努力就无法对实际开发提供足够多的帮助。尽管如此,Flow让你可以简单就获得这种弱化的类型检查,对于现有代码非常有用。

为了解释这种区别,请看下面的例子:

function onlyWorksOnNumbers(x) {
 return x * 10;
}
onlyWorksOnNumbers(‘Hello, world!');

Flow能够发现这个错误(尝试把数字和字符串相乘),然而另一种更加保守的分析需要显式的标注 x 的类型。在这个玩具般的例子里面并不觉得费力,但是在巨型代码库里面几乎无人去做。Flow可以不用添加注释就能发现这个错误 —— 当然前提是开发者想这样做。

类型系统

Flow的类型系统实现了许多期望中的功能。支持标准基本类型( number ,  string , boolean ),类型之间的隐式转换在除一些特殊情形外是被禁止的。结构类型,如函数、对象和数组也被支持。类型可以是多态的。

也许你会感到意外,Flow没有把 null 和 undefined 当成是上述类型中的任何一种。这两种类型会有多种可能,使用这些类型必须在合理检查的保护之上。其它组合类型(如 string | number )也被支持,这种用法同样需要确保安全。Flow知道缩小类型范围时做动态检查的影响。

让我们用一个例子来描述处理 null 值。下面的程序总是在运行时崩溃,但是一般的类型系统会认为它没有问题:

function length(x) {
return x.length;
}
var total = length('Hello') + length(null);

Flow会在编译时期发现这个错误,并指出 x 可以是null( length 属性不应该被访问)。另外,Flow了解这个程序的控制流,所以简单修改就能让这个程序类型正确:

function length(x) {
 if (x !== null) {
 return x.length;
 } else {
 return 0;
 }
}
var total = length('Hello') + length(null);

Flow还了解JavaScript复杂的对象模型:构造器,方法,原型和它们动态扩展以及绑定。已经试验性去支持类型的复杂操作如:绑定对象,抽取keys等等。我们希望未来这些功能使得让为框架指定具体类型成为可能。

类型错误通常报告为定义和实际值不兼容:比如函数调用的参数不足,对象中不包含要访问的属性,或者把字符串当成数字使用。

最后,Flow支持动态类型( any ),这种类型可以绕过类型系统检查:比如可用 any 表示静态分析无法准确判断而报错的location(通常使用反射的情况)。另外Flow在弱模式下遇到上述类型且没有注释类型的话,会自动假定为 any 。

扩展性

为了拓展,Flow根据模块和其它模块的依赖关系以及其它模块提供的类型接口,单独对每个模块进行检查。要生成类型接口,Flow可能需要在模块边界上进行注释。

Flow在一个后台运行的持久化服务器上,维护着整个代码库的语义信息,一开始Flow会对整个代码做一次分析,然后当一系列文件改动的时候(可能是单个文件改动或者在切换分支的时候),服务器会增量式更新改动文件以及由于类型关联的其它相关文件的语义信息。这样,当开发者试图获取类型错误时,它们已经在服务器上了,相应几乎是立即的。这种服务器架构与 Hack 构建在同一种技术之上。

兼容性

Flow致力于支持最新的JavaScript标准。目前已经支持各种ES6特性如destructuring, classes, extended objects, optional function parameters,以及核心API扩展(比如Map, Set, Promise, 和 new methods on Object, Array, 和 Math)。其它特性(尤其是模块)正在开发中。Flow支持CommonJS / Node.js 规范的模块。

var Hello = React.createClass ({
 render: function() {
 return <div>Hello {this.props.name}</div>;
 }
});

如果你在JSX上使用的class名字有错误,Flow会发现这个问题:

React.render(, ...);

而且,如果你在React class里面使用了React.PropTypes规范,你可以对JSX上的attributes做静态类型检查:

var Hello = React.createClass ({
 propTypes: {
 name: React.PropTypes.string.isRequired
 }
 ...
});

Flow就会发现 <Hello/> 缺少属性的错误,或者 <Hello name={42}/> 属性类型的错误。

更多的关于支持React的细节可以在 文档 中找到。

开源

Flow代码大部分用OCaml实现。代码库在活跃更新并且会在未来几个月快速进化。除了在Facebook范围内的数据代码库中运行外,我们希望Flow的分析引擎能用于构建类似的,无论是JavaScript或者其他的语言工具。请让我们知道你是否想加入!

好了,关于Flow之一个新的Javascript静态类型检查器的全部内容先给大家介绍到这里,后续还会持续更新,敬请关注!

Javascript 相关文章推荐
JS获取select-option-text_value的方法
Dec 26 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
Sep 09 Javascript
Javascript生成全局唯一标识符(GUID,UUID)的方法
Feb 27 Javascript
JavaScript实现Base64编码转换
Apr 23 Javascript
JavaScript常用字符串与数组扩展函数小结
Apr 24 Javascript
JavaScript——DOM操作——Window.document对象详解
Jul 14 Javascript
javascript简单实现等比例缩小图片的方法
Jul 27 Javascript
jQuery Easyui DataGrid点击某个单元格即进入编辑状态焦点移开后保存数据
Aug 15 Javascript
JavaScript基础进阶之数组方法总结(推荐)
Sep 04 Javascript
动态加载JavaScript文件的3种方式
May 05 Javascript
JavaScript实现京东放大镜效果
Dec 03 Javascript
vue搜索页开发实例代码详解(热门搜索,历史搜索,淘宝接口演示)
Apr 11 Javascript
jquery实现删除一个元素后面的所有元素功能
Dec 21 #Javascript
浅析JavaScript声明变量
Dec 21 #Javascript
jQuery实现图片文字淡入淡出效果
Dec 21 #Javascript
深入浅析Node.js 事件循环
Dec 20 #Javascript
JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件
Dec 20 #Javascript
基于jQuery和CSS3制作响应式水平时间轴附源码下载
Dec 20 #Javascript
jQuery mobile 移动web(4)
Dec 20 #Javascript
You might like
一个多文件上传的例子(原创)
2006/10/09 PHP
将文件夹压缩成zip文件的php代码
2009/12/14 PHP
php smarty 二级分类代码和模版循环例子
2011/06/01 PHP
PHP新手NOTICE错误常见解决方法
2011/12/07 PHP
利用php实现禁用IE和火狐的缓存问题
2012/12/03 PHP
解析posix与perl标准的正则表达式区别
2013/06/17 PHP
PHP时间处理类操作示例
2018/09/05 PHP
5秒后跳转到另一个页面的js代码
2013/10/12 Javascript
无刷新预览所选择的图片示例代码
2014/04/02 Javascript
14款NodeJS Web框架推荐
2014/07/11 NodeJs
JavaScript中this的9种应用场景及三种复合应用场景
2015/09/12 Javascript
javascript新闻跑马灯实例代码
2020/07/29 Javascript
微信小程序教程系列之新建页面(4)
2017/04/17 Javascript
Bootstrap滚动监听组件scrollspy.js使用方法详解
2017/07/20 Javascript
详解nodejs中express搭建权限管理系统
2017/09/15 NodeJs
vue多页面开发和打包正确处理方法
2018/04/20 Javascript
详解如何从零开始搭建Express+Vue开发环境
2018/07/17 Javascript
jquery 通过ajax请求获取后台数据显示在表格上的方法
2018/08/08 jQuery
详解Angular Forms中自定义ngModel绑定值的方式
2018/12/10 Javascript
nodejs使用async模块同步执行的方法
2019/03/02 NodeJs
JSONObject与JSONArray使用方法解析
2020/09/28 Javascript
Python 时间操作例子和时间格式化参数小结
2014/04/24 Python
python遍历类中所有成员的方法
2015/03/18 Python
初步剖析C语言编程中的结构体
2016/01/16 Python
Python实现删除列表中满足一定条件的元素示例
2017/06/12 Python
python 筛选数据集中列中value长度大于20的数据集方法
2018/06/14 Python
利用Python计算KS的实例详解
2020/03/03 Python
Currentbody法国:健康与美容高科技产品
2020/08/16 全球购物
计算机网络专业自荐信
2014/07/04 职场文书
党员干部群众路线个人整改措施
2014/09/18 职场文书
2016年校园社会综合治理宣传月活动总结
2016/03/16 职场文书
JS继承最简单的理解方式
2021/03/31 Javascript
用Python实现Newton插值法
2021/04/17 Python
python 实现的截屏工具
2021/05/08 Python
解析在浏览器地址栏输入一个URL后发生了什么
2021/06/21 Servers
springboot读取nacos配置文件
2022/05/20 Java/Android