Flow 扫盲

TypeScript 在前端已经深入人心,但依然有一些项目使用 Flow 编写,比如 React 和 Vue 2,这里列出一些 Flow 和 TypeScript 语法不同的地方,方便熟悉 TypeScript 的开发者阅读 Flow 代码。

类型谓语(Type Predicates)

用于标注函数入参类型,Flow 支持多个参数,TypeScript 只支持单个参数。

// @flow
function truthy(a, b): boolean %checks {
  return !!a && !!b;
}

function concat(a: ?string, b: ?string): string {
  if (truthy(a, b)) {
    return a + b;
  }
  return '';
}
type Falsy = false | 0 | '' | null | undefined;

function truthy<T>(x: T | Falsy): x is T {
  return !!x;
}

function concat(a?: string, b?: string): string {
  if (truthy(a) && truthy(b)) {
    return a + b;
  }
  return '';
}

相关链接:

精确对象类型(Exact Object Types)

Flow 支持精确对象类型,TypeScript 目前不支持。

// @flow
function method(obj: {| foo: string |}) {
  // ...
}

var obj = {
  foo: 'test',
  bar: 42
};

method(obj); // Error!
function method(obj: { foo: string }) {
  // ...
}

var obj = {
  foo: 'test',
  bar: 42
};

method(obj); // OK

相关链接:

混合类型(Mixed Types)

类似 TypeScript 中的 unknown

// @flow
function getTypeOf(value: mixed): string {
  return typeof value;
}
// @flow
function stringify(value: mixed) {
  // ...
}

stringify("foo");
stringify(3.14);
stringify(null);
stringify({});

相关链接:

Maybe Types

类似 TypeScript 中的 Optional Parameters,但多了 null 值。

// @flow
function acceptsMaybeNumber(value: ?number) {
  // ...
}

acceptsMaybeNumber(42); // Works!
acceptsMaybeNumber(); // Works!
acceptsMaybeNumber(undefined); // Works!
acceptsMaybeNumber(null); // Works!
acceptsMaybeNumber('42'); // Error!
function f(x?: number) {
  // ...
}

f(); // OK
f(10); // OK

相关链接:

透明类型别名(Opaque Type Aliases)

Flow 允许定义透明类型别名,该别名无法在定义文件之外访问。

// @flow
opaque type ID = string;

相关链接:

类型转换表达式(Type Casting Expressions)

Flow 的类型转换表达式类似 TypeScript 的类型断言(Type Assertion)。

// @flow
let value = 42;

(value: 42);     // Works!
(value: number); // Works!
(value: string); // Error!

let newValue = ((value: any): string);

(newValue: number); // Error!
(newValue: string); // Works!
let value = 42;

value as 42; // Works!
value as number; // Works!
value as string; // Error!

let newValue = value as any as string;

newValue as number; // Error!
newValue as string; // Works!

相关链接:

类型变体(Type Variance)

Flow 支持类型变体,TypeScript不支持。

借助接口属性变体,Flow 中接口属性可以设置为只读或者只写。

// @flow
interface MyInterface {
  +covariant: number;     // read-only
  -contravariant: number; // write-only
}

interface Invariant {  property: number | string }
interface Covariant { +readOnly: number | string }
interface Contravariant { -writeOnly: number }

类的类型变体涉及类的继承特性,以下 *variantOf 语法并不是 Flow 的一部分,仅用来解释变体。

// @flow
class Noun {}
class City extends Noun {}
class SanFrancisco extends City {}

function invariantMethod(value: InvariantOf<City>) {...}

invariantMethod(new Noun());         // error...
invariantMethod(new City());         // okay
invariantMethod(new SanFrancisco()); // error...

function covariantMethod(value: CovariantOf<City>) {...}

covariantMethod(new Noun());         // error...
covariantMethod(new City());         // okay
covariantMethod(new SanFrancisco()); // okay

function contravariantMethod(value: ContravariantOf<City>) {...}

contravariantMethod(new Noun());         // okay
contravariantMethod(new City());         // okay
contravariantMethod(new SanFrancisco()); // error...

function bivariantMethod(value: BivariantOf<City>) {...}

bivariantMethod(new Noun());         // okay
bivariantMethod(new City());         // okay
bivariantMethod(new SanFrancisco()); // okay

相关链接:

名义化类型(Nominal Typing)和结构化类型(Structural Typing)

Flow 中 Function/Object/interface 是结构化类型(Structurally Typed),但 Class 是名义化类型(Nominally Typed),这一点和 TypeScript 不同。

// @flow
class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: string) { /* ... */ } }

let foo: Foo = new Bar(); // Error!
class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: string) { /* ... */ } }

let foo: Foo = new Bar(); // Works!

相关链接:

其他

  • Flow 的 Library Definitions (*.js.flow) 文件对标 TypeScript 的 Declaration File (*.d.ts)
  • flow-typed 项目 对标 DefinitelyTyped 项目,托管了大量第三方库的类型定义
  • Flow 的类型定义文件一般放到项目的 flow-typed 目录下,对标 TypeScript 的 typingstypes

相关链接: