Skip to main content


JavaScript 中有多种类型的值:数字、字符串、布尔值、函数、对象等等。

¥In JavaScript there are many types of values: numbers, strings, booleans, functions, objects, and more.

11234 as number;2"hi" as string;3true as boolean;4[1, 2] as Array<number>;5({prop: "value"}) as {prop: string};6(function func(s: string) {}) as string => void;


¥These values can be used in many different ways:

11 + 2;2"foo" + "bar";3!true;4[1, 2].push(3);5const obj = {prop: "s"};6let value = obj.prop;7obj.prop = "value";8function func(s: string) {}9func("value");


¥All of these different expressions create a new type which is a result of the types of values and the operations run on them.

1let num: number = 1 + 2;2let str: string = "foo" + "bar";

在 Flow 中,每个值和表达式都有一个类型。

¥In Flow every value and expression has a type.


¥Figuring out types statically

Flow 需要一种方法来找出每个表达式的类型。但它不能只是运行你的代码来解决这个问题,如果它这样做了,它会受到你的代码存在的任何问题的影响。例如,如果你创建了一个无限循环,Flow 将永远等待它完成。

¥Flow needs a way to be able to figure out the type of every expression. But it can't just run your code to figure it out, if it did it would be affected by any issues that your code has. For example, if you created an infinite loop Flow would wait for it to finish forever.

相反,Flow 需要能够通过分析值而不运行它来确定值的类型(静态分析)。它会遍历所有已知的类型,并开始弄清楚它们周围的所有表达式会产生什么结果。

¥Instead, Flow needs to be able to figure out the type of a value by analyzing it without running it (static analysis). It works its way through every known type and starts to figure out what all the expressions around them result in.

例如,要计算出以下表达式的结果,Flow 需要首先计算出它的值是什么。

¥For example, to figure out the result of the following expression, Flow needs to figure out what its values are first.

val1 + val2;

如果值是数字,则表达式的结果是数字。如果值是字符串,则表达式结果将是字符串。这里有许多不同的可能性,因此 Flow 必须查找这些值是什么。

¥If the values are numbers, then the expression results in a number. If the values are strings, then the expression results in a string. There are a number of different possibilities here, so Flow must look up what the values are.

如果 Flow 无法确定每个值的确切类型,则 Flow 必须确定每个可能的值是什么,并进行检查以确保其周围的代码仍然适用于所有可能的类型。

¥If Flow is unable to figure out what the exact type is for each value, Flow must figure out what every possible value is and check to make sure that the code around it will still work with all of the possible types.


¥Soundness and Completeness

当你运行代码时,单个表达式将仅使用一组有限的值运行。但 Flow 仍然检查每个可能的值。通过这种方式,Flow 检查了太多的东西或者过度近似了有效的代码。

¥When you run your code, a single expression will only be run with a limited set of values. But still Flow checks every possible value. In this way Flow is checking too many things or over-approximating what will be valid code.

通过检查每个可能的值,Flow 可能会捕获代码运行时实际上不会发生的错误。Flow 这样做是为了成为 "声音"。

¥By checking every possible value, Flow might catch errors that will not actually occur when the code is run. Flow does this in order to be "sound".


¥In type systems, soundness is the ability for a type checker to catch every single error that might happen at runtime. This comes at the cost of sometimes catching errors that will not actually happen at runtime.


¥On the flip-side, completeness is the ability for a type checker to only ever catch errors that would happen at runtime. This comes at the cost of sometimes missing errors that will happen at runtime.


¥In an ideal world, every type checker would be both sound and complete so that it catches every error that will happen at runtime.

Flow 试图尽可能健全和完整。但由于 JavaScript 不是围绕类型系统设计的,Flow 有时必须做出权衡。当这种情况发生时,Flow 倾向于注重健全性而不是完整性,以确保代码没有任何错误。

¥Flow tries to be as sound and complete as possible. But because JavaScript was not designed around a type system, Flow sometimes has to make a tradeoff. When this happens Flow tends to favor soundness over completeness, ensuring that code doesn't have any bugs.

只要 Flow 不会太吵闹而影响你的工作效率,稳定性就可以。有时,当健全性太妨碍你时,Flow 反而会偏向于完整性。Flow 只在极少数情况下执行此操作。

¥Soundness is fine as long as Flow isn't being too noisy and preventing you from being productive. Sometimes when soundness would get in your way too much, Flow will favor completeness instead. There's only a handful of cases where Flow does this.


¥Other type systems will favor completeness instead, only reporting real errors in favor of possibly missing errors. Unit/Integration testing is an extreme form of this approach. Often this comes at the cost of missing the errors that are the most complicated to find, leaving that part up to the developer.