用Flow提高前端健壮性

看一段常见代码:

//例1
function foo(x) {
  return x + 10
}
foo('Hello!')

//例2
function main(params){
   //fn1函数获取了一个数据
   var object = fn1(params)
   //fn2根据获数据,产生一个结果
   var result = fn2(object)

   return result
}
复制代码

例2很明显,这个过程很是的‘黑’,若是你想知道object包含什么数据的话,能够:javascript

  1. 打印一下 console.log(object)
  2. 查看fn1的注释,而且保佑它的注释是正确,全面的
  3. 或结合1,2,而后仔细查看fn1的源码,但愿它不是很复杂

被上述步骤折磨完以后,终于能真正的写点代码了,可是依旧得很是当心,由于这里还有另外一个函数:fn2java

在修改代码的时候,得保证result这个结果没有被影响,那么如何保证呢?react

很简单,重复上面的步骤,搞清楚result包含的数据,在测试的时候确保其数据跟原先的相同。 ...bash

动态类型一时爽,代码重构火葬场 知乎传送门:为何说“动态类型一时爽,代码重构火葬场”babel

是时候完全优化这个烦人的问题了angular2

引入类型系统

其实问题的根源就是由于javascript太灵活了,在代码运行期间几乎能够作任何的修改,框架

没有东西能够在代码层面保证 某个变量,某个函数 跟预期的一致函数

因此要加入类型系统来确保代码的可靠性,在后期维护的时候一样可以传达出有效的信息工具

Flow & TypeScript

Flow是个JavaScript的静态类型检查工具,由Facebook出品的开源码项目,问世只有两三年,是个至关年轻的项目。简单来讲,它是对比TypeScript语言的解决方式。学习

会有这类解决方案,原由是JavaScript是一种弱(动态)数据类型的语言,弱(动态)数据类型表明在代码中,变量或常量会自动依照赋值变动数据类型,并且类型种类也不多,这是直译式脚本语言的常见特性,但有多是优势也是很大的缺点。优势是容易学习与使用,缺点是像开发者常常会由于赋值或传值的类型错误,形成不如预期的结果。有些时候在使用框架或函数库时,若是没有仔细看文件,亦或是文件写得不清不楚,也容易形成误用的状况。

这个缺点在应用规模化时,会显得更加严重。咱们在团队开发协同时,通常都是经过统一的代码规范,来下降这个问题的发生,但JS语言自己没法有效阻止这些问题TypeScript这样的强(静态)类型的JavaScript超集语言就开始流行,用严格的角度,以JavaScript语言为基底,来从新打造另外一套具备强(静态)类型特性的语言,就如同Java或C#这些语言同样,这也是为何TypeScript称本身是企业级的开发JavaScript解决方案。

TypeScript存在的问题

TypeScript天然有它的市场,但它有一些明显的问题:

  • 首先是JavaScript开发者须要再进一步学习,内容很多
  • 有必定陡峭的学习曲线
  • 已经在使用的应用代码,须要整个改用TypeScript代码语法,才能发挥完整的功用。这对不少已经有内部代码库的大型应用开发团队而言,将会是个重大的决定,由于若是不往全面重构的路走,将没法发挥强(静态)类型语言的最大效用eg:angular2

因此许多现行的开源码函数库或框架,并不会直接使用TypeScript做为代码的语言,另外一方面由于TypeScript并不是是普及到必定程度的语言。 固然TypeScript也是个活跃的开源码项目,发展到如今也有一段时间,它的背后有微软公司的支持,全新打造过的Angular2框架中(由Google主导),也采用了TypeScript做为基础的开发语言

Flow你的新选择

如今,Flow提供了另外一个新的选项,它是一种强(静态)类型的辅助检查工具Flow的功能是让现有的JavaScript语法能够事先做类型的声明(定义),在开发过程当中进行自动检查,固然在最后编译时,同样能够用babel工具来移除这些标记

相较于TypeScript是另外从新制定一套语言,最后再通过编译为JavaScript代码来运行。Flow走的则是非强制与非侵入性的路线。

Flow的优势

  • 且易学易用 它的学习曲线没有TypeScript来得高,虽然内容也不少,但半天学个大概,就能够渐进式地开始使用
  • Flow从头至尾只是个检查工具 不是新的程序语言或超集语言,因此它能够与各类现有的JavaScript代码兼容,若是你哪天不想用了,就去除掉标记就是回到原来的代码,没什么负担

so

选择flow.js工具而不选择TypeScript强类型语言的缘由显而易见? flow.js对工程的侵入性很小,无需大量的额外工做就能使用起来

从一个小例子演示

这种类型不符的状况在代码中很是容易发生,例如上面的例1:

function foo(x) {
  return x + 10
}

foo('Hello!')
复制代码

x这个传参,咱们在函数声明时但愿它是个数字类型,但最后使用调用函数时则用了字符串类型。最后的结果会是什么吗? "Hello!10",这是由于加号(+)在JavaScript语言中,除了做为数字的加运算外,也能够看成字符串的链接运算。想固然这并非咱们想要的结果。

聪明如你应该会想要用类型来当传参的识别名,容易一眼看出传参要的是什么类型,像下面这样:

function foo(number) {
  return number + 10
}
复制代码
  • 若是在复合类型的状况,例如这个传参的类型能够是数字类型也能够是布尔类型,你又要如何写得清楚?
  • 若是是个复杂的对象类型时,结构又该如何先肯定好?
  • 另外还有函数的返回类型又该如何来写?

利用Flow类型的定义方式,来解决这个小案例的问题,能够改写为像下面的代码:

// @flow

function foo(x: number): number {
  return x + 10
}

foo('hi')
复制代码

当使用非数字类型的值做为传入值时,就会出现由Flow工具发出的警告消息,像下面这样:

[flow] Cannot call foo with 'hi' bound to x because string 1 is incompatible with number 2. (a.getting-start.js:6:5)

若是是要容许多种类型也是很容易能够加标记的,假使这个函数可使用布尔与数字类型,但返回能够是数字或字符串,就像下面这样修改过:

// @flow

function foo(x: number | boolean): number | string {
  if (typeof x === 'number') {
    return x + 10
  }
  return 'x is boolean'
}

foo(1)
foo(true)
foo(null)  // 这一行有类型错误消息
复制代码

在多人协同开发某个有规模的JavaScript应用时,这种类型的输出输入问题就会很常碰见。若是利用Flow工具的检查,能够避免掉许多没必要要的类型问题

真实案例

可能你会认为Flow工具只能运用在小型代码中,其实否则,Vue源码中大量使用flowjs中类型检测:

此处输入图片的描述

Flow使用

此处输入图片的描述

  1. flow init
  2. // @flow 或 /* @flow */
  3. IDE插件 或 flow check 在Visual Studio Code中由于它内建TypeScript与JavaScript的检查功能,若是要使用Flow工具来做类型检查,须要在用户设置中,加上下面这行设置值以避免冲突:

"javascript.validate.enable": false

4 . babel插件在编译时就会一并转换Flow标记

{
  "plugins": [
    "transform-flow-strip-types"
  ]
}
复制代码

Flow支持的数据类型

Flow支持原始数据类型,以下面的列表:

  • boolean
  • number
  • string
  • null
  • void

类型别名&常见语法

// @flow
export type Test = {
  titleOne?: string,
  titleTwo: ?string
}
var a: Test = {titleOne:"3",titleTwo:4}

var b:string = ""
//any
export type NavigationGestureDirection = 'horizontal' | 'vertical';

type T = Array<string>
var x: T = []
x["Hi"] = 2 //有Flow警告

type TT = Array<Test>
var xx:TT = []
xx = [{titleOne: '1',
  titleTwo: false}]

type MyObject = {
  foo: number,
  bar: boolean,
  baz: string,
};

let val:MyObject = {foo:2,bar:false,baz:'444'};
var val1: MyObject = {foo:2,bar:false,baz:null};
var val2: MyObject = {foo:2,bar:false};
function method(val: MyObject):MyObject { return {foo:2,bar:false,baz:'2'}} 
class Foo { constructor(val: MyObject) { /* ... */ } }
复制代码

React中的应用

若是你在React class里面使用了React.PropTypes规范,你能够对JSX上的attributes作静态类型检查:

var Hello = React.createClass ({
  propTypes: {
    name: React.PropTypes.string.isRequired
  }
  ...
});
//<Hello/> //Flow就会发现 缺乏属性的错误
//<Hello name={42}/>//属性类型的错误
复制代码
import * as React from 'react';

type Props = {
  foo: number,
  bar?: string,
};

function MyComponent(props: Props) {
  props.doesNotExist; // Error! You did not define a `doesNotExist` prop.

  return <div>{props.bar}</div>;
}

<MyComponent foo={42} />
复制代码

更多关于支持React的细节 请移步 https://flow.org/en/docs/react/components/

Flow将来的发展??

相关文章
相关标签/搜索