如何避免在模块声明中重复类型定义?

How do I avoid repeating type definitions in module declarations?

免责声明: 总的来说,我对 Flow 和静态类型还是有些陌生,所以我很可能忽略了一些东西 easy/obvious这个问题。

假设我有一个名为 my-library 的图书馆。该库向其用户公开一个模块 index.js,它导入几个其他模块(moduleA.jsmoduleB.js)供内部使用。

我想将 Flow 与此库一起使用,既用于我自己的内部开发,也用于 index.js.flow 文件中,该文件为同样使用 Flow 的库用户提供模块声明。所以文件结构看起来像这样:

- index.js
- index.js.flow (contains the module declaration for library users)
- moduleA.js
- moduleA.js.flow (just exported type definitions, no module declaration)
- moduleB.js
- moduleB.js.flow (just exported type definitions, no module declaration)

问题是 index.js.flow 模块声明需要使用来自 moduleA.js.flowmoduleB.js.flow 的类型。 (我有 moduleA.js.flowmoduleB.js.flow 而不是直接在 .js 文件中定义类型的原因是 .js 文件中的类型定义将被 Babel 删除,我希望它们对于图书馆用户来说仍然存在于某个地方。

我知道以下内容不会对导入的外部 JS 进行类型检查 my-module:

index.js.flow(这个不行)

import type { SomeType } from './moduleA'

declare module 'my-module' {
  declare function exports(): {
    someMethod: () => SomeType
  }
}

SomeType 在导入时在模块声明中似乎不可用,但在本地定义它确实有效:

index.js.flow(有效)

export type SomeType = string

declare module 'my-module' {
  declare function exports(): {
    someMethod: () => SomeType
  }
}

所以一种解决方案是只定义和导出 index.js.flow 中的所有类型,然后 moduleA.jsmoduleB.js 导入它们(而不包括 .js.flow 文件对于 moduleAmoduleB),但是将所有类型定义都放在根流文件中而不是 .js.flow 文件中与这些类型源自的模块相匹配似乎很奇怪。

或者,我知道我可以在各自的开发模块中定义类型,然后在 index.js.flow 模块声明中再次定义它们,但我不想在中重复类型定义如果可能的话,两个不同的地方。

如果您能帮助我找出最好的组织方式,我将不胜感激。 (再一次,我知道我很有可能在做一些愚蠢的事情或忽略了一些明显的事情。)

.js.flow 文件的目的是完全 与您实施中相应的 .js 文件一样,除了[=41] =] 它们不是由 Babel 翻译的。特别是,它们就像相应的 .js 文件一样导入和导出内容。此外,就像 .js 文件根据其在文件系统中的位置自动与模块关联一样,.js.flow 文件也是如此。

按照问题中的例子,假设 index.jsmodule.exports 是一个函数,returns 一个包含 属性 someMethod 的对象类型 () => SomeType,其中类型 SomeTypemoduleA.js 导出。然后我们可以在 index.js.flow 中有以下内容:

// @flow

import type { SomeType } from './moduleA'

declare module.exports: () => {
  someMethod: () => SomeType;
};

以及 moduleA.js.flow 中的以下内容:

// @flow

export type SomeType = string;

假设我们将 index.js.flowmoduleA.js.flow 放在 src/node_modules/my-module/ 中,我们可以通过在 src/ 中的 test.js 中添加以下内容来测试我们的设置是否正确]:

// @flow

var foo = require('my-module');

(foo().someMethod(): number); // error (string incompatible with number)