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 的typings
、types
相关链接: