跳至主要内容

声明文件

什么是声明文件?

让我们看看一种更通用、有时更方便的为模块声明类型的方式:.flow 文件。

根据是否存在实现文件,有两种可能的用例。

在第一种情况下,模块的导出类型在声明文件 <FILENAME>.flow 中声明,该文件位于与相应的实现文件 <FILENAME> 相同的目录中。声明文件完全覆盖了同位置的实现。换句话说,Flow 将完全忽略 <FILENAME>,而只读取 <FILENAME>.flow

在第二种情况下,实现文件完全缺失。<FILENAME>.flow 被视为名为 <FILENAME> 的文件。

请注意,.flow 扩展名既适用于 .js 文件,也适用于 .json 文件。相应的声明文件分别具有扩展名 .js.flow.json.flow

现在让我们看一个上面记录的第一种情况的例子。假设我们在一个名为 src/LookBeforeYouLeap.js 的文件中拥有以下代码

import { isLeapYear } from "./Misc";
if (isLeapYear("2020")) console.log("Yay!");

并假设 src/Misc.js 拥有一个与 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 中拥有以下声明。

注意:声明文件中的声明语法与我们在 创建库定义部分 中看到的相同。

1declare export function isLeapYear(year: string): boolean;

你认为会发生什么?

没错,src/LookBeforeYouLeap.js 中的 isLeapYear 调用将通过类型检查,因为 year 参数在声明文件中期望一个 string

如本例所示,声明文件必须谨慎编写:确保它们正确是程序员的责任,否则它们可能会隐藏类型错误。

在常规代码中内联声明

有时在实现文件的源代码中内联声明非常有用。

在以下示例中,假设你想完成编写函数 fooList,而不想先费心模拟其依赖项:一个接受 number 并返回 string 的函数 foo,以及一个拥有 map 方法的类 List。你可以通过包含 Listfoo 的声明来做到这一点

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}

只是别忘了用正确的实现替换声明。