ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## Array(数组)类型 要创建一个数组类型,可以使用`Array<Type>`类型,其中 Type 是数组中元素的类型。例如,为你使用的数字数组创建一个类型`Array<number>`,这样子就会限定数组中的值只能使用数字的数据类型。当然你也可以加入埀直线(|)来定义允许多种类型,例如`Array<number|string>`。 ``` // @flow let arr1: Array<number> = [1, 2, 3]; // 成功! let arr2: Array<number> = [1, '2', true]; // 报错!'2' 和 true 并非是number类型。 let arr3: Array<number | string | boolean> = [1,'2',true]; // 成功! let arr4: Array<mixed> = [1,'2',true]; // 声明一个元素是任意类型的数组 arr4 = [true, 1]; // 重新赋值 arr4 = ['']; // 重新赋值 ``` 暂时就介绍这么多,还有一些类型文章中没有提到,更多更详细的内容请在Flow官网的[Array Types](https://flow.org/en/docs/types/arrays/)章节中查看。 </br> ## Object(对象)类型 对象类型会尝试尽可能多地匹配JavaScript中对象的语法,也是使用大括号`{}`和`key:value`这样的键值对来表示,用`,`隔开各个键值对。 ``` // @flow var obj1: { foo: boolean } = { foo: true }; var obj2: { foo: number, bar: boolean, baz: string, } = { foo: 1, bar: true, baz: 'three', }; ``` **可选的对象属性** 即对象类型可以具有可选属性。 在JavaScript中,访问不存在的属性,返回的结果为`undefined`。这是JavaScript程序中常见的错误,因此Flow将这些错误转换为类型错误。 ``` // @flow var obj = { foo: "bar" }; obj.bar; ``` 运行一下FLow,显示的结果如下, >Error ------------------------------------------------------------------------------------------------- src/index.js:4:1 >Cannot get `obj.bar` because property `bar` is missing in object literal [1]. >  src/index.js:4:1 >  4| obj.bar;    ^^^^^^^ >References: >  src/index.js:2:11 >  2| var obj = { foo: "bar" };         ^^^^^^^^^^ [1] >Found 1 error 如果对象有时没有属性,可以通过添加问号`?`使其成为可选属性,问号`?`位于属性名称后面,`{属性名称?: 类型}`。 ``` // @flow var obj: { foo?: boolean } = {}; obj.foo = true; // 成功! obj.foo = 'hello'; // 报错! ``` 值得注意的是,可选属性值可以是`void`或省略(什么都不写),但是不能是`null`。 ``` // @flow function acceptsObject(value: { foo?: string }) { // ... } acceptsObject({ foo: "bar" }); // 成功! acceptsObject({ foo: undefined }); // 成功! acceptsObject({}); // 成功! acceptsObject({ foo: null }); // 报错! ``` ### 对象类型推导 Flow有两种不同的方式推导出对象字面量的类型。 #### Sealed objects(密封的对象) 在Flow中创建一个密封的对象类型的方法是创建一个带有属性的对象。密封的对象知道你声明的所有属性及其值的类型。 ``` // @flow var obj = { foo: 1, bar: true, baz: 'three' }; var foo: number = obj.foo; // 成功! var bar: boolean = obj.bar; // 成功! var baz: null = obj.baz; // 报错! var bat: string = obj.bat; // 报错! ``` Flow不允许你为密封对象添加新的属性。 ``` // @flow var obj = { foo: 1 }; obj.bar = true; // 报错! obj.baz = 'three'; // 报错! ``` 这里的解决方法是将对象转换为未密封的对象。 #### Unsealed objects(未密封的对象) 在Flow中创建一个未密封的对象类型的方法是创建一个带没有属性的对象。未密封的对象不知道你声明的所有属性及其值的类型,并且允许你为其添加新的属性。 ``` // @flow var obj = {}; obj.foo = 1; // 成功! obj.bar = true; // 成功! obj.baz = 'three'; // 成功! var foo: number = obj.foo; // 成功! ``` #### 为未密封对象属性重新赋值 与`var`和`let`变量相似,你可以改变未密封的对象的属性值。Flow会为你设置可能的类型。 ``` // @flow var obj = {}; if (Math.random()) obj.prop = true; else obj.prop = "hello"; var val1: boolean = obj.prop; // 报错! var val2: string = obj.prop; // 报错! var val3: boolean | string = obj.prop; // 成功! var val4: boolean | string | number = obj.prop; // 成功! var val5: mixed = obj.prop; // 成功! ``` 上一章节说过,Flow会对代码进行动态检查,由于obj.prop的类型可能为`boolean`或者`string`,所以接收改属性的变量类型也应该是(至少)能够接收这两种类型的变量,给单一类型的变量的赋值是会失败的。 当然,当Flow可以确定重新分配后的属性类型时,Flow会为其分配确定的类型。 ``` // @flow var obj = {}; obj.prop = true; obj.prop = "hello"; var val1: boolean = obj.prop; // 报错! var val2: string = obj.prop; // 成功! ``` #### 未密封对象上的未知属性查找是不安全的 未密封的对象允许随时写入新的属性。Flow确保读取与写入兼容,但不能确保写入发生在读取之前(按执行顺序)。**这意味着Flow对于从未密封对象中读取未知属性查,并且进行其它写入的这种行为是不做检查的。** ``` var obj = {}; obj.foo = 1; obj.bar = true; var foo: number = obj.foo; // 成功! var bar: boolean = obj.bar; // 成功! var baz: string = obj.baz; // 成功!?这里确实是成功了。 ``` *Flow的这种不安全行为,未来可能被改进。* ### 确切的对象类型 在Flow中,在预期正常对象类型的情况下传递具有额外属性的对象是安全的。 ``` // @flow function method(obj: { foo: string }) { // ... } method({ foo: "test", bar: 42 }); ``` 上面的这种写法是允许的,也是安全的。 > 这是一种通常被称为[“宽度子类型”](https://link.jianshu.com/?t=https%3A%2F%2Fflow.org%2Fen%2Fdocs%2Flang%2Fwidth-subtyping%2F)的子类型,因为“更宽”(即具有更多属性)的类型是更窄类型的子类型。 不过,有时候你的代码就只需要传入你想要的类型数据,并不想传入一些不必要的数据,那么这时候阻止这种行为并且只允许一组特定的属性是必要的。为此,Flow有了以下的做法, ``` {| foo: string, bar: number |} ``` 与常规对象类型不同,将具有“额外”属性的对象传递给确切的对象类型是无效的。 ``` // @flow var foo: {| foo: string |} = { foo: "Hello", bar: "World!" }; // 报错! ``` > Error ------------------------------------------------------------------------------------------------ src/index.js:2:30 > Cannot assign object literal to `foo` because property `bar` is missing in object type [1] but exists in object literal [2]. >  src/index.js:2:30 >  2| var foo: {| foo: string |} = { foo: "Hello", bar: "World!" };                ^^^^^^^^^^^^^^^^^^^^^^^^^ [2] >References: >  src/index.js:2:10 >  2| var foo: {| foo: string |} = { foo: "Hello", bar: "World!" };        ^^^^^^^^^^^^^ [1] >Found 1 error </br> 关于`Object`类型,更多更详细的内容请在Flow官网的[Object Types](https://flow.org/en/docs/types/objects/)章节中查看。