声明文件
什么是声明文件?
¥What's a Declaration File?
让我们看一下更通用、有时更方便的声明模块类型的方法:.flow 文件。
¥Let's look at a more general, and sometimes more convenient way to
declare types for modules: .flow files.
有两种可能的用例,具体取决于实现文件是否存在。
¥There are two possible use cases, depending on whether an implementation file exists or not.
在第一种情况下,模块的导出类型在声明文件 <FILENAME>.flow 中声明,该文件与相应的实现文件 <FILENAME> 位于同一目录中。声明文件完全遮蔽了共置实现。换句话说,Flow 将完全忽略 <FILENAME>,而只读取 <FILENAME>.flow。
¥In the first case, the exported types of a module are declared in a declaration
file <FILENAME>.flow, that is located in the same directory as the corresponding implementation
file <FILENAME>. The declaration file completely shadows the colocated
implementation. In other words, Flow will completely ignore <FILENAME> and just
read <FILENAME>.flow instead.
在第二种情况下,实现文件完全丢失。<FILENAME>.flow 被视为如同命名为 <FILENAME> 一样。
¥In the second case, the implementation file is missing entirely. <FILENAME>.flow
is treated as if it is named <FILENAME>.
请注意,.flow 扩展名既适用于 .js 文件也适用于 .json 文件。相应的声明文件的扩展名分别为 .js.flow 和 .json.flow。
¥Note that the .flow extension applies both to .js files as well as .json
ones. The corresponding declaration files have extensions .js.flow and .json.flow,
respectively.
现在让我们看一下上面记录的第一个案例的示例。假设我们在文件 src/LookBeforeYouLeap.js 中有以下代码:
¥Now let's see an example of the first case documented above. Suppose we have the
following code in a file src/LookBeforeYouLeap.js:
import { isLeapYear } from "./Misc";
if (isLeapYear("2020")) console.log("Yay!");
并假设 src/Misc.js 有 isLeapYear 的不兼容实现:
¥and suppose that src/Misc.js has an incompatible implementation of isLeapYear:
1export function isLeapYear(year: number): boolean {2 return year % 4 == 0; // yeah, this is approximate3}如果我们现在创建一个声明文件 src/Misc.js.flow,则将使用其中的声明而不是 src/Misc.js 中的代码。假设我们在 src/Misc.js.flow 中有以下声明。
¥If we now create a declaration file src/Misc.js.flow, the declarations in it
will be used instead of the code in src/Misc.js. Let's say we have the
following declarations in src/Misc.js.flow.
注意:声明文件中的声明语法与我们在 创建库定义部分 中看到的相同。
¥NOTE: The syntax for declarations in a declaration file is the same as we've seen in Creating Library Definitions section.
1declare export function isLeapYear(year: string): boolean;你认为会发生什么?
¥What do you think will happen?
是的,src/LookBeforeYouLeap.js 中的 isLeapYear 调用将进行类型检查,因为 year 参数需要声明文件中的 string。
¥Right, the isLeapYear call in src/LookBeforeYouLeap.js will typecheck, since
the year parameter expects a string in the declaration file.
如本例所示,必须小心编写声明文件:程序员需要确保它们是正确的,否则它们可能会隐藏类型错误。
¥As this example shows, declaration files must be written with care: it is up to the programmer to ensure they are correct, otherwise they may hide type errors.
常规代码中的内联声明
¥Inlining declarations in regular code
有时,将声明内联作为实现文件源的一部分很有用。
¥Sometimes it is useful to make declarations inline, as part of the source of an implementation file.
在下面的示例中,假设你想要完成函数 fooList 的编写,而不需要首先模拟其依赖:一个接受 number 并返回 string 的函数 foo,以及一个具有 map 方法的类 List。你可以通过包含 List 和 foo 的声明来做到这一点:
¥In the following example, say you want to finish writing
the function fooList without bothering to mock up its dependencies first: a
function foo that takes a number and returns a string, and a class
List that has a map method. You can do this by including declarations for
List and foo:
1declare class List<T> {2 map<U>(f: (x: T) => U): List<U>;3}4declare function foo(n: number): string;5
6function fooList(ns: List<number>): List<string> {7 return ns.map(foo);8}只是不要忘记用正确的实现替换声明。
¥Just don't forget to replace the declarations with proper implementations.