跳至主要内容

创建库定义

在花费时间编写自己的 libdef 之前,我们建议您查看是否已经存在针对您要处理的第三方代码的 libdef。flow-typed 是一个 工具和仓库,用于在 Flow 社区中共享常见的 libdef - 因此,它是一种很好的方法,可以解决您项目中可能需要的任何公共 libdef 的大部分问题。

但是,有时可能不存在预先存在的 libdef,或者您有非公开的第三方代码,或者您确实需要自己编写 libdef。为此,您将首先为要编写的每个 libdef 创建一个 .js 文件,并将它们放在项目根目录的 /flow-typed 目录中。在这些 libdef 文件中,您将使用一组特殊的 Flow 语法(如下所述)来描述相关第三方代码的接口。

声明全局函数

要声明一个应该在整个项目中可访问的全局函数,请在 libdef 文件中使用 declare function 语法

flow-typed/myLibDef.js

1declare function foo(a: number): string;

这告诉 Flow 项目中的任何代码都可以引用 foo 全局函数,并且该函数接受一个参数(一个 number)并返回一个 string

声明全局类

要声明一个应该在整个项目中可访问的全局类,请在 libdef 文件中使用 declare class 语法

flow-typed/myLibDef.js

1declare class URL {2  constructor(urlStr: string): URL;3  toString(): string;4
5  static compare(url1: URL, url2: URL): boolean;6}

这告诉 Flow 项目中的任何代码都可以引用 URL 全局类。请注意,此类定义没有任何实现细节 - 它只定义类的接口。

声明全局变量

要声明一个应该在整个项目中可访问的全局变量,请在 libdef 文件中使用 declare vardeclare letdeclare const 语法

flow-typed/myLibDef.js

1declare const PI: number;

这告诉 Flow 项目中的任何代码都可以引用 PI 全局变量 - 在这种情况下,它是一个 number

声明全局类型

要声明一个应该在整个项目中可访问的全局类型,请在 libdef 文件中使用 declare type 语法

flow-typed/myLibDef.js

1declare type UserID = number;

这告诉 Flow 项目中的任何代码都可以引用 UserID 全局类型 - 在这种情况下,它只是 number 的别名。

声明模块

通常,第三方代码是根据模块而不是全局变量来组织的。要编写一个声明模块存在的 libdef,您需要使用 declare module 语法

declare module "some-third-party-library" {
// This is where we'll list the module's exported interface(s)
}

declare module 之后用引号指定的名称可以是任何字符串,但它应该与您在项目中使用 requireimport 来访问第三方模块时使用的字符串相同。有关定义通过相对 require/import 路径访问的模块的信息,请参阅有关 .flow 文件 的文档

declare module 块的主体中,您可以指定该模块的导出集。但是,在我们开始讨论导出之前,我们必须讨论 Flow 支持的两种模块:CommonJS 和 ES 模块。

Flow 可以处理 CommonJS 和 ES 模块,但在使用 declare module 时,两者之间存在一些相关差异,需要考虑。

声明 ES 模块

ES 模块 有两种导出:命名导出和默认导出。Flow 支持在 declare module 主体中声明这两种导出中的任何一种或两种,如下所示

命名导出

flow-typed/some-es-module.js

declare module "some-es-module" {
// Declares a named "concatPath" export
declare export function concatPath(dirA: string, dirB: string): string;
}

请注意,您也可以在 declare module 的主体中声明其他内容,这些内容将作用域到 declare module 的主体 - 但它们不会从模块中导出

flow-typed/some-es-module.js

declare module "some-es-module" {
// Defines the type of a Path class within this `declare module` body, but
// does not export it. It can only be referenced by other things inside the
// body of this `declare module`
declare class Path {
toString(): string;
}

// Declares a named "concatPath" export which returns an instance of the
// `Path` class (defined above)
declare export function concatPath(dirA: string, dirB: string): Path;
}
默认导出

flow-typed/some-es-module.js

declare module "some-es-module" {
declare class URL {
constructor(urlStr: string): URL;
toString(): string;

static compare(url1: URL, url2: URL): boolean;
}

// Declares a default export whose type is `typeof URL`
declare export default typeof URL;
}

也可以在同一个 declare module 主体中声明命名默认导出。

声明 CommonJS 模块

CommonJS 模块有一个导出值(module.exports 值)。要在 declare module 主体中描述此单个值的类型,您将使用 declare module.exports 语法

flow-typed/some-commonjs-module.js

declare module "some-commonjs-module" {
// The export of this module is an object with a "concatPath" method
declare module.exports: {
concatPath(dirA: string, dirB: string): string;
};
}

请注意,您也可以在 declare module 的主体中声明其他内容,这些内容将作用域到 declare module 的主体,但它们不会从模块中导出

flow-typed/some-commonjs-module.js

declare module "some-commonjs-module" {
// Defines the type of a Path class within this `declare module` body, but
// does not export it. It can only be referenced by other things inside the
// body of this `declare module`
declare class Path {
toString(): string;
}

// The "concatPath" function now returns an instance of the `Path` class
// (defined above).
declare module.exports: {
concatPath(dirA: string, dirB: string): Path
};
}

注意:由于给定模块不能同时是 ES 模块和 CommonJS 模块,因此在同一个 declare module 主体中混合 declare export [...]declare module.exports: ... 是错误的。