【Flow】快速⼊门Flow.js类型注释#React源码基础知识
快速⼊门Flow.js 类型注释
前⾔
最近在看React.js,可能⼤家知道在React中,很⼤⼀部分源码都是⽤Flow.js写的,有时候会看不懂是什么意思。所以阅读源码之前,还是有必要快速看⼀下Flow.js的语法的。
简介
那Flow.js是什么框架呢?其实它和最近⼏年⾮常流⾏的TypeScript类似,是⼀个静态类型检查器,我们知道JavaScript是⼀个弱类型语⾔,在⼤型项⽬、框架实⾏的过程中,这种弱类型特征会带来⼀些意想不到的Bug等风险,所以需要引⼊类型检查器,从根本上避免类型带来的Bug。
Vue3.js就引⼊了TypeScript,React.js在构建的时候,TypeScript并不成熟,Facebook内部⾸先构建了⾃⼰的类型检查系统Flow.js,我们要知道Flow实际上是⼀个内部开源项⽬,它⾸先是为React和其他Facebook的JS框架服务的,因此学习Flow.js在我们实际编写上收获并不会⽐TS⼤,作者编写本⽂的⽬的也是仅仅为了希望阅读React源码的读者能够看懂源码的程度,⽤⼀个词来说就是浅尝辄⽌。
⽐较特殊的,需要注意的东西会包含在本⽂,特别基础、不需要知道也能看出来什么意思的不在本⽂的内容范围。
快速开始
本节给出Flow.js声明类型的快速⽰例。
// @flow
function concat(a: string, b: string){
return a + b;
}
concat("A","B");// 成功
concat(1,2);// 错误
我们在参数上设置了类型边界(string),在接收到错误类型时Flow会报错。
类型注释
本节将简明给出所有类型的注释⽅法。
原始类型
原始类型包括:
Booleans
Strings
Numbers
null
undefined (void in Flow types)
Symbols (new in ECMAScript 2015)
原始类型有两种:
字⾯值
true;
"hello";
3.14;
null;
undefined;
包装器对象
new Boolean(false);
new String("world");
new Number(42);
在Flow中声明原始值分为⼩写(字⾯值)和⾸字母⼤写(包装器对象)。Booleans
声明为boolean类型之后,只接受true, false 以及表达式判断。
/
/ @flow
function acceptsBoolean(value: boolean){
// ...
}
acceptsBoolean(true);// 成功
acceptsBoolean(false);// 成功
acceptsBoolean(0);// 错误
acceptsBoolean("foo");// 错误
acceptsBoolean(Boolean(0));// 成功
acceptsBoolean(!!0);// 成功
Numbers
需要注意的是,NaN和Infinity都是可接受的。其他略。
Strings
如果需要串联{}和[],需要加上String()toString()JSON.stringify()等⽅法。
// @flow
"foo"+String({});
"foo"+[].toString();
""+JSON.stringify({})
null和void
在Flow⾥,null和void是两种类型,分别处理null和undefined
可选对象属性
可选对象属性可以省略、其他类型,单单不能是null:
/
/ @flow
function acceptsObject(value:{ foo?: string }){
// ...
}
acceptsObject({ foo:"bar"});// 成功
acceptsObject({ foo:undefined});// 成功
acceptsObject({ foo:null});// 错误
acceptsObject({});// 成功
可选⽅法参数
同上
⽅法参数默认值
function method(value: string ="default"){/* ... */}
可接受void、string、⽆参数,但不接受null参数
字⾯类型
⽤来限定参数只能是设定的字⾯值
// @flow
function getColor(name:"success"|"warning"|"danger"){
switch(name){
case"success":return"green";
case"warning":return"yellow";
case"danger":return"red";
}
}
getColor("success");// 成功
getColor("danger");// 成功
// $ExpectError
getColor("error");// 错误
混合类型(mixed)
设定多种混合类型时,⽤|分割
多种可能类型
function stringifyBasicValue(value: string | number){return''+ value;}
设定为和参数类型⼀致
function identity<T>(value:T):T{return value;}
设定为混合类型
function getTypeOf(value: mixed): string {return typeof value;}
在设定mixed之后,如果要使⽤传⼊的值,⾸先要判断值的类型,否则会报错,Flow有⼀个完善(refinement)的概念。// @flowfunction stringify(value: mixed) { // $ExpectError return "" + value; // Error!}stringify("foo");
// @flow
function stringify(value: mixed){
if(typeof value ==='string'){
return""+ value;// 成功
}else{
return"";
}
}
stringify("foo");
if (typeof value === 'string') 完善value的类型之后,在if的上下⽂内,value的类型被限定为string
任何类型(any)
any⽤于跳出类型检查,原则上是不实⽤的。
防⽌any泄露
在any类型的参数被引⽤赋值之后,any类型会泄露到其他变量上,最终会影响到所有代码。
所以在遇到any类型,需要⼿动完善:
// @flow
function fn(obj: any){
let foo: number = obj.foo;
}
可能类型(Maybe)
在类型前加上?来设定可能类型,可能类型接受本⾝类型、空值和未定义:
// @flowfunction acceptsMaybeNumber(value: ?number) { // ...}acceptsMaybeNumber(42); // 成功acceptsMaybeNumber(); // 成功acceptsMaybe Number(undefined); // 成功acceptsMaybeNumber(null); // 成功acceptsMaybeNumber("42"); // 错误
对象属性为可能类型时,对象属性不能不定义。
// @flowfunction acceptsMaybeProp({ value }: { value: ?number }) { // ...}acceptsMaybeProp({ value: undefined }); // 成功acceptsMaybeProp({}); // 错误
完善可能类型,在使⽤可能类型之前,可以完善使其的类型确定:
⽅法有 value !== null && value !== undefined 或 value != null 或 typeof value === 'number' (number为设定的可能类型)
变量类型
在变量定义中规定类型:
// @flowlet foo = 42;let isNumber: number = foo; // 成功foo = true;let isBoolean: boolean = foo; // 成功 foo = "hello";let isString: string = foo; // 成功
有⼀些特殊的场景下,Flow的类型判断会失效:
// @flowlet foo = 42;function mutate() { foo = true; foo = "hello";}mutate();// $ExpectErrorlet isString: string = foo; // 错误
函数类型
函数有两个地⽅需要设定类型:参数和返回值
function method(str, bool,...nums){// ...}function method(str: string, bool?: boolean, ...nums: Array<number>): void { // ...}
let method=(str, bool,...nums)=>{// ...};let method = (str: string, bool?: boolean, ...nums: Array<number>): void => { // ...};
this函数
在JS中每个⽅法都可以⽤this调⽤,在Flow中,可以在第⼀个参数设定this的类型
// @flowfunction method<T>(this: { x: T }) : T { return this.x;}var num: number = method.call({x : 42});var str: string = method.call({x : 42}); // error
谓语函数
在if条件中的表达式转移到⼀个新的函数的时候,在函数定义时加上%checks 标注:
function truthy(a, b): boolean %checks {return!!a &&!!b;}function concat(a:?string, b:?string): string {if(truthy(a, b)){return a + b;}return'';}
对象类型
在Flow⾥有两种对象类型:确切对象类型和⾮确切对象类型,⽂档推荐使⽤确切对象类型。
// @flowvar obj1: { foo: boolean } = { foo: true };var obj2: { foo: number, bar: boolean, baz: string,} = { foo: 1, bar: true, baz: 'three',};
可选对象类型属性
在Flow中,访问⼀个对象中不存在的属性会报错。
在属性后加?标注,使该属性可选,该属性值不能为null
对象⽅法
对象的⽅法属性只读。
// @flowlet b = { foo() { return 3; }}b.foo = () => { return 2; } // 错误
对象的⽅法引⽤⾃⾝时⽤对象名⽽⾮this
// @flow
let a ={
x :3,
foo(){return this.x;}// 错误
}
let b ={
x :3,
foo(){return b.x;}// 成功
}
对象类型推断
密封对象
创建⼀个带有属性的对象之后,Flow将其认作密封对象,对象的属性⾃带类型。并且⽆法在密封对象中增加属性
⾮密封对象
创建⼀个没有属性的对象之后,Flow将其认作⾮密封对象,后续可添加属性。
重分配⾮密封对象属性
和变量类型表现⼀致,Flow会赋予属性所有可能的类型:
// @flow
var obj ={};
if(Math.random()) obj.prop =true;
else obj.prop ="hello";
// $ExpectError
var val1: boolean = obj.prop;// Error!
// $ExpectError
var val2: string = obj.prop;// Error!
var val3: boolean | string = obj.prop;// Works!
确切对象类型
typeof array(React源码中常⽤)通常传⼀个有多余属性的对象是可以的,如果需要严格规定传⼊对象的属性,需要使⽤确切对象类型:
{| foo: string, bar: number |}
这个时候传递多余的属性就会报错。
(React源码中常⽤)如果需要结合确切对象的属性,不能⽤交集,⽽要⽤对象属性扩散⽅法
// @flowtype FooT = {| foo: string |};type BarT = {| bar: number |};type FooBarFailT = FooT & BarT;type FooBarT = {| ...FooT, ...BarT |};const fooBarFail: F ooBarFailT = { foo: '123', bar: 12 }; // 错误const fooBar: FooBarT = { foo: '123', bar: 12 }; // 成功
明确的不确切对象类型
虽然有点绕弯⼦,但是这样也能定义⼀个不确切对象类型:
// @flowtype Inexact = {foo: number, ...};
定义Map对象
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论