## Maybe(可能)类型
Maybe类型用一个`?`在类型前面表示,包含类型本身、`null`、`undefined`。
```
// @flow
/* demo1 */
let hello: ?string; // 声明一个数据类型可以是 string, null, undefined 的变量
hello = null; // 赋值
hello = undefined; // 重新赋值
hello = 'hello'; // 重新赋值
hello = 1; // 报错!
hello = true; // 报错!
/* demo2 */
function acceptsMaybeString(value: ?string) {
// ...
}
acceptsMaybeString("bar"); // 成功!
acceptsMaybeString(undefined); // 成功!
acceptsMaybeString(null); // 成功!
acceptsMaybeString(); // 成功!
```
</br>
## Optional(可选)类型
>Optional一般用于对象属性或者函数参数,在名称后面加一个`?`,包含类型本身、`undefined`,注意,这里不包括`null`类型。
**可选的对象属性**
即对象类型可以具有可选属性,问号`?`位于属性名称后面。
```
{ propertyName?: string }
```
除了它们的设定值类型之外,这些可选属性也可以被`void`完全省略。但是不能是`null`。
```
// @flow
function acceptsObject(value: { foo?: string }) {
// ...
}
acceptsObject({ foo: "bar" }); // 成功!
acceptsObject({ foo: undefined }); // 成功!
acceptsObject({ foo: null }); // 报错!
acceptsObject({ foo: true}); // 报错!
acceptsObject({}); // 成功!
```
**可选的函数参数**
即函数可以具有可选参数,其中问号`?`出现在参数名称后面。同样,该参数不能为`null`。
```
// @flow
function acceptsOptionalString(value?: string) {
// ...
}
acceptsOptionalString("bar"); // 成功!
acceptsOptionalString(undefined); // 成功!
acceptsOptionalString(null); // 报错!
acceptsOptionalString(); // 成功!
```
</br>
## Literal(字面文字)类型
>字面文字类型指的是以真实值作为数据类型,可用的值有三种,即数字、字符串或布尔值。
```
// @flow
/* demo1 */
let hello: 'hello'; // 声明一个只能赋值 'hello' 的变量
hello = 'hello'; // 赋值成功!
hello = 'hi'; // 报错!
hello = 12; // 报错!
hello = undefined; // 报错!
hello = null; // 报错!
/* demo2 */
function method(param: 1 | 'hi' | boolean): void { /* ... */ }
method(); // 报错,缺少参数
method(1); // 成功!
method(1.2); // 报错,类型不对
method('hi'); // 成功!
method('hello'); // 报错,类型不对
method(true); // 成功!
method(false); // 成功!
```
</br>
## Mixed(混合)类型
Mixed类型是指任意数据类型。
```
// @flow
let hello: mixed; // 声明一个 mixed 类型的变量
hello = 'hello'; // 赋值
hello = true; // 重新赋值
hello = 12; // 重新赋值
hello = undefined; // 重新赋值
hello = null; // 重新赋值
```
有时候我们并不能确定需要的值到底是哪种类型,这时候我们可以使用混合类型来表示,但在使用该值之前,我们需要判断该值到底是哪种类型,否则会引起错误。
```
// @flow
function stringify(value: mixed) {
return "" + value;
}
stringify("foo");
```
如上面代码,运行之后就报错了,
> Error ----------------------------------------------------------------------------------------------- src/index.js:12:10
> Cannot add empty string and `value` because mixed [1] could either behave like a string or like a number.
> src/index.js:12:10
> 12| return "" + value; // Error!
> ^^^^^^^^^^
>References:
> src/index.js:10:27
> 10| function stringify(value: mixed) {
> ^^^^^ [1]
>Found 1 error
原因是虽然输入时可以用`mixed`,但Flow会认为函数中`value`的值不见得可以与`string`类型作相加,所以会请求你要在函数中的代码,要加入检查对传入类型在运行期间的类型检查代码,例如像下面修改过才能过关:
```
// @flow
function stringify(value: mixed) {
if (typeof value === 'string' || typeof value === 'number') {
return "" + value;
} else {
return value;
}
}
stringify("foo");
```
从上面的例子可以看到Flow除了对类型会作检查外,它也会请求对某些类型需要有动态的检查。在官方的文件可以参考[Type Refinements](https://flow.org/en/docs/lang/refinements/#_)这个章节。
</br>
## Any(任意)类型
如果你想要一种方法来选择不使用类型检查器,或是还在开发中正在调试时,有一种作为渐进的改善代码的类型。
`Any`类型就可以做到这一点。但是切记,使用`Any`是不安全的,因为会失去类型检查,应尽可能避免使用。
例如,下面的代码不会报告任何提示:
```
// @flow
function add(one: any, two: any): number {
return one + two;
}
add(1, 2); // 成功!
add("1", "2"); // 成功!
add("1", 2); // 成功!
add({}, []); // 成功!
```
当然还不止上面的问题,使用`Any`类型还可能会出现即使是会导致运行时错误的代码也不会被Flow捕获。
```
// @flow
function getObjProperty(obj: any) {
return obj.a.b;
}
getObjProperty({}); // No Errors !
```
上面这段代码明显错误(Uncaught TypeError: Cannot read property 'b' of undefined),但是由于`Any`类型的存在,Flow并没有捕捉到错误,反而通过了检查。
</br>
## Type Alias(类型别名)
`Type Alias`提供了可以预先定义与集中代码中所需要的类型,一个简单的例子如下:
```
// @flow
type T = Array<string>;
let x: T = [];
x["Hi"] = 2; // 报错!
```
`Type Alias`也可以用于复杂的应用情况,详见Flow官网提供的[Type Aliases](https://flowtype.org/docs/type-aliases.html)这一章节。
## Union(联合)类型
所有的类型都可以使用垂直线符号`|`作为联合使用(也就是 OR 的意思),例如`string | number`指的是两种类型其中一种都可使用,这是一种联合的类型,称为`Union`类型。
```
// @flow
type U = number | string;
let x: U = 1; // 成功!
x = "two"; // 成功!
x = true; // 报错!
```
</br>