flow-type-transformer
v1.0.6
Published
Transform value/types easily in Flow
Downloads
10
Maintainers
Readme
Flow-Type Transformer
Transforming types in Flow can quickly become a bit cumbersome to do properly. This package is an extremely tiny (+-500 bytes) value transformer which attempts to simplify transforming values while maintaining 100% flow coverage.
It exports some basic flow utility-types that can then be used to compose your transformation.
Note: When using the package in development, flow types from the package are retained.
Why?
The actual functionality of this package is extremely simple and generally not very difficult to implement outside of the package. However, we have found that the implementation can often cause hiccups and coverage annoyances.
With flow-type-transformer
we make the transformation of values feel like a first-class feature of Flow. It provides a simple utility at runtime and a much more useful utility during development (stronger typing and coverage).
Installation
yarn add flow-type-transformer
or
npm install --save flow-type-transformer
Overview
flow-type-transformer
exports a factory function which returns an instance of TypeTransformer
which can then be used to transform your values while maintaining type checking.
A transform is really just a simple proxy to some value transformation function which makes it easier to interface with flow in a way that is standard. We hope to include pre-built transforms that are able to take in common values and transform them at some point (likely as a separate package).
In reality, the transformer is actually returning your transform function directly. The instance is used simply to annotate the transformation in a way that flow can understand.
For now, take a look at the
transforms
folder and thetests/flow
folder for examples.
Note: If you have useful transform functions that you'd be ok with including in our transforms package, pull requests are more than welcome for those!
Runtime Exports
The runtime export should not add any noticeable performance hit to your application. It ends up following the simple pattern of createTransformer: tranformer => transformer
during runtime. A microsecond or two during initialization and 0 after that.
import createTransformer from 'flow-type-transformer'
createTypeTransformer(fn)
(default)
The default export of the package. Simply takes a $Transformer
function and returns the same function. Our magic happens because in the middle we are able to teach Flow the expected input/output in a way that is both functional and re-useable.
function createTypeTransformer<Before, After>(
fn: $Transformer<Before, After>,
): $Transform<Before, After>
If you prefer, createTypeTransformer is also exported as a named module which can be imported via
import { createTypeTransformer } from 'flow-type-transformer'
Type / Flow Exports
This package exports various Flow types that can be used in your project. These will be stripped from the project completely when you strip the flow-types.
They can be imported using the syntax:
import type { $Transform, $Transformer } from 'flow-type-transformer'
interface $Transform
(Interface)
The $Transform
interface is how we will define our type transformation when we call our factory function. It takes two parameters: <Before, After>
where Before
is the type that will be given to the transform function and After
will be the resulting output.
interface $Transform<Before, After> {
transformer: $Transformer<Before, After>,
$call(v: Before): After,
}
In reality, your transformer function is directly returned and the interface is used simply to help Flow understand your transformation.
type $Transformer
(Function)
The type used to define our transform function. It simply take a value of type Before
and returns a value of type After
. Your transformer function must follow this signature or Flow will complain.
type $Transformer<Before, After> = (value: Before) => After;
const stringToNumberTransformer: $Transformer<string, number> = str => Number(str)
Note that you should not generally not need to import or use this type at all. Since we are using it internally, Flow will inform you if your transformer does not appear to match the expected signature.
Examples
Below are some simplified examples. In general all examples will maintain 100% flow coverage. Some that are shown here may be simplified. For more examples be sure to browse through the flow examples
Create a Transformer
flow-type-transformer
default exports a factory function which returns a class implementing the $Transform
interface. It expects a transformer function which takes your input type as input and outputs your output type.
/* @flow */
import type { $Transform } from 'flow-type-transformer';
import createTransformer from 'flow-type-transformer';
// pointless transformer example (since Flow can infer this)
const stringToNumber: $Transform<string, number> = createTransformer(str => Number(str))
const n = stringToNumber('1')
Simple Example
Below is an extremely simple example which Flow actually implements a solution for natively using the $NonMaybeType
, but it is a nice way to illustrate what is going on.
For the sake of simplicity the example below is not providing type annotations on the transform function itself.
Note: The example with 100% flow coverage as well as type-casting examples to show the benefits of strongly typed projects can be found in the array-filter-simple flow-test source.
Note: The transformer will cast the
After
value in its response - it is up to the transform function to make sure it is performing the necessary transformation. Standard Flow type handling will ensure this is done properly.
/* @flow */
import type { $Transform } from 'flow-type-transformer';
import createTransformer from 'flow-type-transformer';
// $Transformer<Array<mixed>, Array<string>>
const transformer = v => v.filter(el => typeof el === 'string')
const transform: $Transform<Array<?string>, Array<string>> = createTransformer(transformer);
const before = ['one', undefined, 'two', null];
const after = transform(before);
(before: Array<string>); // $ExpectError
(after: Array<string>); // $Works
Since Flow now knows the signature of the returned instance, it can provide us with all of it's Flow goodness:
/*
$ExpectError
array literal
This type is incompatible with the expected param type of
array type
---
Type argument `T` is incompatible:
number
---
This type is incompatible with
string
---
*/
transform([1]);
Definitely stroll through the flow examples as they provide some more advanced examples and include error traces, etc. to give a better idea of what is going on.
Contributing
While I can't imagine there is much need to modify the source (let me know if you notice something), always appreciate pull requests to help provide more examples and transforms for others to use!
Just submit a pull request!