flow

1. types

1.1 Primitive Types

Types for literal values are lowercase.

// @flow
function method(x: number, y: string, z: boolean) {
  // ...
}

method(3.14, "hello", true);

Types for the wrapper objects are capitalized (the same as their constructor).

// @flow
function method(x: Number, y: String, z: Boolean) {
  // ...
}

method(new Number(42), new String("world"), new Boolean(false));

string

// @flow
function acceptString(value: string) {
  console.log(value)
}

acceptString('str' + 'foo')         // works
acceptString('str' + 42)            // works
acceptString('str' + {})            // error
acceptString('str' + [])            // error

acceptString('str' + {}.toString()) // works
acceptString('str' + String([]))    // works

null&undefined

Flow treats these as separate types: null and void (for undefined).

// @flow
function acceptsUndefined(value: void) {
  /* ... */
}
acceptsUndefined(undefined)         // works

Function parameters with defaults

// @flow
function acceptsOptionalString(value: string = "foo") {
  // ...
}

acceptsOptionalString("bar");     // Works!
acceptsOptionalString(undefined); // Works!
acceptsOptionalString(null);      // Error!
acceptsOptionalString();          // Works!
1.2 Literal Types
// @flow
// string
function getColor(name: "success" | "warning" | "danger") {
  switch (name) {
    case "success" : return "green";
    case "warning" : return "yellow";
    case "danger"  : return "red";
  }
}

getColor("success"); // Works!
getColor("danger");  // Works!
// $ExpectError
getColor("error");   // Error!

// number
function acceptsTwo(value: 2) {
  // ...
}

acceptsTwo(2);   // Works!
// $ExpectError
acceptsTwo(3);   // Error!
// $ExpectError
acceptsTwo("2"); // Error!
1.3 Mixed Types
function stringifyBasicValue(value: string | number | boolean) {
  return '' + value;
}

When you try to use a value of a mixed type you must first figure out what the actual type is or you’ll end up with an error.

// @flow
function stringify(value: mixed) {
  // $ExpectError
  return "" + value; 
}

stringify("foo");
// Error! This type cannot be used in an addition
// because it is unkonwn whether it behaves like a number or a string

// @flow
function stringify(value: mixed) {
  if (typeof value === 'string') {
    return "" + value; // Works!
  } else {
    return "";
  }
}

stringify("foo");       // works
1.4 Any Types
// @flow
function fn(obj: any) /* (:number) */ {
  let foo: number = obj.foo;
  let bar /* (:number) */ = foo * 2;
  return bar;
}

let bar /* (:number) */ = fn({ foo: 2 });
let baz /* (:string) */ = "baz:" + bar;
1.5 Maybe Types
// @flow
function acceptsMaybeNumber(value: ?number) {
  if (value !== null && value !== undefined) {
    return value * 2;
  }
}

function acceptsMaybeNumber(value: ?number) {
  if (value != null) {
    return value * 2;
  }
}

function acceptsMaybeNumber(value: ?number) {
  if (typeof value === 'number') {
    return value * 2;
  }
}
1.6 Function Types
function method(str, bool, ...nums) {
  // ...
}

function method(str: string, bool?: boolean, ...nums: Array<number>): void {
  // ...
}

// Arrow Functions
let method = (str: string, bool?: boolean, ...nums: Array<number>): void => {
  // ...
}

Function Types

(str: string, bool?: boolean, ...nums: Array<number>) => void
// You may also optionally leave out the parameter names
(string, boolean | void, Array<number>) => void
// You might use these functions types for something like a callback
function method(callback: (error: Error | null, value: string | null) => void) {
    // ...
}

Rest Parameters

function method(...args: Array<number>) {
    // ...
}

Function Returns

function method(): number {
  // ...
}

Return types ensure that every branch of your function returns the same type. This prevents you from accidentally not returning a value under certain conditions.

// @flow
// $ExpectError
function method(): boolean {
  if (Math.random() > 0.5) {
    return true;
  }
}
1.7 Object Types

Accessing a property that doesn’t exist evaluates to undefined.If an Object sometimes donesn’t have a property,use optional object type.

// @ flow
var obj: { foo?: boolean } = {}
obj.foo = true          // works

Sealed objects

// @flow
var obj = {
  foo: 1,
  bar: true,
  baz: 'three'
};

var foo: number  = obj.foo; // Works!
var bar: boolean = obj.bar; // Works!
// $ExpectError
var baz: null    = obj.baz; // Error!
var bat: string  = obj.bat; // Error!
// @flow
var obj = {
  foo: 1
};

// $ExpectError
obj.bar = true;    // Error!
// $ExpectError
obj.baz = 'three'; // Error!

Unsealed objects

// @flow
var obj = {};

obj.foo = 1;       // Works!
obj.bar = true;    // Works!
obj.baz = 'three'; // Works!

var obj = {};
obj.foo = 42;
var num: number = obj.foo;

Exact object types

function foo(onj:{| foo: string, bar: number |}) {
  // ...
}
foo({foo: 'str', bar: 1})           // works
foo({foo: 'str', bar: 1, baz: 2})   // error
1.8 Type Aliases
// @flow
type MyObject = {
  foo: number,
  bar: boolean,
  baz: string,
};

These type aliases can be used anywhere a type can be used

var val: MyObject = { / *... * / }
function method(params: MyObject) = { / *... * / }
class Foo { constructor(val: MyObject) { / *... * / } }
1.9 Interface Types
// @flow
class Foo {
  serialize() { return '[Foo]'; }
}

class Bar {
  serialize() { return '[Bar]'; }
}

// $ExpectError
const foo: Foo = new Bar(); // Error!

Instead, you can use interface in order to declare the structure of the class that you are expecting

interface Serializable {
    serizalize(): string
}

class Foo {
  serialize() { return '[Foo]'; }
}

class Bar {
  serialize() { return '[Bar]'; }
}

const foo: Serializable = new Foo(); // Works!
const bar: Serializable = new Bar(); // Works!

implements

You can also use implements to tell Flow that you want the class to match an interface. This prevents you from making incompatible changes when editing the class.

// @flow
interface Serializable {
  serialize(): string;
}

class Foo implements Serializable {
  serialize() { return '[Foo]'; } // Works!
}

class Bar implements Serializable {
  // $ExpectError
  serialize() { return 42; } // Error!
}

Interface property variance

// @flow
// + read-only
interface Invariant {  property: number | string; }
interface Covariant { +readOnly: number | string; }

function method1(value: Invariant) {
  value.property;        // Works!
  value.property = 3.14; // Works!
}

function method2(value: Covariant) {
  value.readOnly;        // Works!
  // $ExpectError
  value.readOnly = 3.14; // Error!
}

// - write-only
interface Invariant     {  property: number; }
interface Contravariant { -writeOnly: number; }

var numberOrString = Math.random() > 0.5 ? 42 : 'forty-two';

// $ExpectError
var value1: Invariant     = { property: numberOrString };  // Error!
var value2: Contravariant = { writeOnly: numberOrString }; // Works!
1.10 Union Types
type Numbers = 1 | 2;
type Colors = 'red' | 'blue'

type Fish = Numbers | Colors;

Disjoint Unions

// @flow
// Trying to combine these two separate types into a single one will only cause us trouble
type Response = {
  success: boolean,
  value?: boolean,
  error?: string
};

function handleResponse(response: Response) {
  if (response.success) {
    // $ExpectError
    var value: boolean = response.value; // Error!
  } else {
    // $ExpectError
    var error: string = response.error; // Error!
  }
}

Instead, if we create a union type of both object types, Flow will be able to know which object we’re using based on the success property.

// create a union type of both object types
type Success = { success: true, value: boolean };
type Failed  = { success: false, error: string };

type Response = Success | Failed;

function handleResponse(response: Response) {
  if (response.success) {
    var value: boolean = response.value; // Works!
  } else {
    var error: string = response.error; // Works!
  }
}

Disjoint unions with exact types

You cannot distinguish two different objects by different properties.

// @flow
type Success = { success: true, value: boolean };
type Failed  = { error: true, message: string };

function handleResponse(response:  Success | Failed) {
  if (response.success) {
    // $ExpectError
    var value: boolean = response.value; // Error! property 'value' not found in object type
  }
}

Flow checks not beyond judgement, so it’s result is no connection with if.

However, to get around this you could use exact object types.

// @flow
type Success = {| success: true, value: boolean |};
type Failed  = {| error: true, message: string |};

type Response = Success | Failed;

function handleResponse(response: Response) {
  if (response.success) {
    var value: boolean = response.value;
  } else {
    var message: string = response.message;
  }
}

With exact object types, we cannot have additional properties, so the objects conflict with one another and we are able to distinguish which is which.

1.11 Typeof Types
// @flow
let num1 = 42;
let num2: typeof num1 = 3.14;     // Works!
// $ExpectError
let num3: typeof num1 = 'world';  // Error!

let bool1 = true;
let bool2: typeof bool1 = false;  // Works!
// $ExpectError
let bool3: typeof bool1 = 42;     // Error!

let str1 = 'hello';
let str2: typeof str1 = 'world'; // Works!
// $ExpectError
let str3: typeof str1 = false;   // Error!

let obj1 = { foo: 1, bar: true, baz: 'three' };
let obj2: typeof obj1 = { foo: 42, bar: false, baz: 'hello' };

let arr1 = [1, 2, 3];
let arr2: typeof arr1 = [3, 2, 1];

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值