Our team have been using Flow types for some time at Red Badger and we’ve seen some real benefits. Namely, more robust code that is easier and safer to refactor, and significant productivity gains thanks to excellent tooling with the Nuclide IDE (thanks Facebook!).
Yesterday I watched an excellent Strangeloop talk on clojure.spec:
For those unfamiliar, it’s a specification language for the dynamically typed language Clojure. It allows developers to specify the shape of some data a function expects, and specify some invariants that should be satisfied before or after execution. It seems somewhat inspired by design by contract and there are some definite overlaps with the kind of guarantees provided by a type system.
However — the powerful idea behind clojure.spec is that enforcement of these specifications is completely left up to the developer. Albeit aided by some built in utility functions. For this to work, the specifications must be available at runtime.
Statically typed languages commonly only make usage of type information at compile time. Yet, languages such as C# and Java have also had mechanisms for accessing type information at runtime, as part of a “Reflection API”, for a long time.
Furthermore, users of Flow normally run their JS code through Babel, where flow-strip-types removes any annotations and outputs executable code. In order to retain type information, we can instead replace this plugin with flow-runtime-types, a small transform library I wrote for this purpose.
flow-runtime-types exposes the AST of our Flow annotations to runtime code, we can then interpret this AST to build some interesting features.
The AST looks like this:
Quite simple to understand, and low level enough to build some tooling that takes advantage of it.
At the edges of any system, type checked or otherwise, it is necessary to implement validation logic to ensure data is in the correct shape. When using Flow, encoding these rules once as part of the type system, and again as part of executable code can feel redundant.
Instead, we could utilise the Flow annotations AST to produce automatic runtime validation of the data.
I chose to convert the flow types into a Joi schema object (https://github.com/hapijs/joi) so validation can be handled by a battle tested library. For example, using the above type definitions:
This doesn’t mean we can remove all other validation logic, as there is no way to encode arbitrary constraints (e.g. the max length of a string) in Flow. It does however save us from the tedium of structural validation, so we can instead focus on validating the semantic meaning of the data.
I’ve implemented this as a proof of concept for primitive and generic types in Flow, and it seems to work effectively. We could certainly also use this approach to completely replace runtime propType validation in React components.
We can also use the Flow AST to generate valid fixtures to use in unit or property based tests. Usage as follows:
We can execute this function many times over to produce random, but valid, output for our system. We can then directly use this in property based tests or fuzz testing (as seen in tools such as https://github.com/carteb/carte-blanche) when applied to UI programming.
One limitation of this approach is that runtime introspection is only available for explicit type declarations. One of the major benefits of Flow is type inference. Addressing this limitation could take one of the following approaches:
Can you think of any other use cases for runtime type introspection? Or an easier way to achieve it?
A proof of concept is available here on GitHub, not yet distributed to NPM:
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising &sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!
Create your free account to unlock your custom reading experience.