声明文件
什么是声明文件?
¥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.