Skip to main content

声明文件

什么是声明文件?

¥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.jsisLeapYear 的不兼容实现:

¥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。你可以通过包含 Listfoo 的声明来做到这一点:

¥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.