user3056783
user3056783

Reputation: 2644

Creating JS library that uses flow type and exposes types

I am writing a library that will be consumed by 3rd party. I chose flowtype as a typing system (for specific reasons due to my organization). The library exposes annotated React component.

The library is annotated using flowtype. I also want to be able to use it in other code with flowtype. I created index.flow.js in the library and put following in it:

// @flow

import type MyComponent from './components/my-component'

export default MyComponent

// some other types follow
...

When I try to use the library in different codebase, the types "do not work". For example if I pass invalid prop to the component, the type system does not throw any errors. My codebase is typed using flowtype as well.

Should I declare my React in component in library's index.flow.js file? That seems awkward because now I have to maintain the types at two places (the component itself and the flow file).

I was thought that the flow works by default. Since my React component is typed and the library is exposing index.flow.js it would recognize that the component has specific types for props, state etc. but it does not.

Upvotes: 1

Views: 743

Answers (1)

user3056783
user3056783

Reputation: 2644

So after some researching I've come to conclusion that there are two approaches:

1. Expose single definition file

Make sure to create definition file as same as your distribution JS filename. This means if you have library lib-a with bundled file lib-a.js, name the definition file lib-a.js.flow. Follow Flow documention on creating library definitions on how to correctly define your module.

With this approach you need to declare the whole module inside it. It means if you have a class MyComponent, you need to define it here again.

I didn't like this approach because everything needs to be in one place. In you source code you then need to import the types from the definition file so you don't end up duplicating type definitons. This is not so great, for example with React you end up importing Props type from the main definition file which makes it less readable instead of having the types in-line. This approach can be good for small libraries I guess.

2. Use source file .flow suffix

Using this approach you basically copy all your non-transpiled / un-bundled source code with distribution file. These files will end with *.flow extension which means that Flow will pick these up only for type analysis. Read this article on how to get it working.

In short you basically:

  1. Install flow-copy-source as dev dependency
  2. Add this to package.json:

    "build:flow": "flow-copy-source -v -i '**/__tests__/**' src lib"
    

    Where src is the folder of your source code and lib is the folder of your distribution file(s) which are eventually consumed (and probably in npm repository).

One could argue that this approach is "hacky" and pollutes the distribution package. I agree, it's not very clean solution but probably the best I've found so far. Please read the provided article and the comments to get more insight on what other things you could do.

Changes coming (?)

I have come across this Github thread where this exact problem is being discussed. It seems like gen-flow-files is about to be removed and my used approach is the way forward for now.

Upvotes: 1

Related Questions