flow-runtime
flow-runtime copied to clipboard
Type Refinement Function Generation
This is a:
- [ ] Bug Report
- [ ] Feature Request
- [x] Question
- [ ] Other
Which concerns:
- [x] flow-runtime
- [x] babel-plugin-flow-runtime
- [ ] flow-runtime-validators
- [ ] flow-runtime-mobx
- [ ] flow-config-parser
- [ ] The documentation website
Consider a program that ought to:
- Take a string as input.
- Parses this string as JSON.
- If JSON conforms to a flow type (
User
), continue, otherwise throw an exception and halt. - Evaluate some total function over the aforementioned type.
Let's say the type that we'd like to validate against in Step #3 is:
type User = {
name: string,
id: number
}
For step #2 I can write something like:
export type JSON = | string | number | boolean | null | JSONObject | JSONArray
export type JSONObject = { [key:string]: JSON }
export type JSONArray = JSON[]
export const typedJSON = (x: mixed) : JSON => {
switch (typeof x) {
case 'object':
if (x === null) {
return x
} else if (Array.isArray(x)) {
return x.map(typedJSON)
}
const o: JSONObject = {}
for (const k in x) {
o[k] = typedJSON(x[k])
}
return o
case 'string':
case 'number':
case 'boolean':
return x
default:
throw new Error('Invalid JSON')
}
}
I could also manually write a function with the signature (j: JSON) => User
that checks for the presence of the name
/id
keys and ensures their values are a string and number respectively, throwing an exception otherwise. How can I generate such validation functions from flow definitions with flow-runtime
and ensure that flow infers the correct return type?
Is this something you would be amenable to supporting?
@bwestergard maybe I'm missing something, but it seems like you could accomplish this with something like:
function parseUser(input: string): User {
return JSON.parse(input);
}
Or is the issue that you'd like to do this in production without the rest of flow-runtime's overhead?
Yes, I'd like to use a library like flow-runtime
in production to do runtime validation and be assured by flow that the validation function has the right type. See this comment.
I spent a long time looking into this a couple of months ago, what I wanted (and still do want) is to be able to take a Flow (runtime) type, convert it to JSON Schema and back again. It turned out to be a lot of work to get right, especially as ideally the conversion happens at compile time so that you don't need to include flow-runtime in prod, but that again turns into a huge can of worms. It is possible to fix these things, but I can't see myself having a full week or two to do the work any time in the near future. If you do have the time and the inclination I could give you some pointers on where to start?
@bwestergard How about this?
import { reify } from 'flow-runtime';
import type { Type } from 'flow-runtime';
const user = (reify: Type<User>).assert(json);
You'll need to apply the babel plugin: https://github.com/codemix/flow-runtime/tree/master/packages/babel-plugin-flow-runtime