Disclaimer: I'm still somewhat new Flow and static typing in general, so it's very possible I'm overlooking something easy/obvious with this question.
Say I have a library called my-library
. The library exposes a single module to its users, index.js
, which imports a couple other modules (moduleA.js
and moduleB.js
) for internal use.
I want to use Flow with this library, both for my own development internally, and in a index.js.flow
file with a module declaration for users of the library who are also using Flow. So the file structure would look something like this:
- 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)
The issue is that the index.js.flow
module declaration needs to use types from both moduleA.js.flow
and moduleB.js.flow
. (The reason I have moduleA.js.flow
and moduleB.js.flow
instead of just defining the types directly in the .js files is that the type definitions in the .js files will be stripped out by Babel, and I want them to still exist somewhere for library users).
I know that the following does not type check with external JS that imports my-module
:
index.js.flow (this doesn't work)
import type { SomeType } from './moduleA'
declare module 'my-module' {
declare function exports(): {
someMethod: () => SomeType
}
}
SomeType doesn't seem to be useable in the module declaration when it's imported, but defining it locally does work:
index.js.flow (this works)
export type SomeType = string
declare module 'my-module' {
declare function exports(): {
someMethod: () => SomeType
}
}
So one solution is to just define and export all types from within index.js.flow
, and just have moduleA.js
and moduleB.js
import them (and not include .js.flow
files for moduleA
and moduleB
), but it seems weird to have all of the type definitions in the root flow file instead of in the .js.flow
files matching the modules that those types originate from.
Alternatively, I know I could define the types in their respective modules for development, and just define them again in the index.js.flow
module declaration, but I'd prefer not to have to repeat the type definitions in two different places if possible.
I would greatly appreciate any help figuring out how best to organize this. (And again, I know there's a pretty solid chance I'm doing something dumb or overlooking something obvious.)
The purpose of .js.flow
files is to act exactly like the corresponding .js
files in your implementation, except that they are not translated by Babel. In particular, they import and export things just like the corresponding .js
files do. Also, just like a .js
file is automatically associated with a module based on where it resides in the file system, so is a .js.flow
file.
Following the example in the question, let's say index.js
's module.exports
is a function that returns an object containing a property someMethod
of type () => SomeType
, where the type SomeType
is exported by moduleA.js
. Then we can have the following in index.js.flow
:
// @flow
import type { SomeType } from './moduleA'
declare module.exports: () => {
someMethod: () => SomeType;
};
And the following in moduleA.js.flow
:
// @flow
export type SomeType = string;
Assuming that we put index.js.flow
and moduleA.js.flow
in src/node_modules/my-module/
, we can test that our setup is correct by having the following in test.js
in src/
:
// @flow
var foo = require('my-module');
(foo().someMethod(): number); // error (string incompatible with number)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With