Flow: Runtime Type Introspection

Created on 13 Oct 2016  路  5Comments  路  Source: facebook/flow

This is a question and not directly actionable, so feel free to close it

Do the "core team" have any thoughts on exposing Flow type annotations to runtime code? I've written up some thoughts/use-cases and a PoC with a very naive way to achieve this here:

It would be great to understand if this kind of thing is on your radar at all, and how you might achieve it given the current/future direction of Flow.

Note: https://github.com/facebook/flow/issues/248, https://github.com/facebook/flow/issues/2566 seem heavily related. But thoughts beyond the implementation details in those issues would be interesting 馃憤

feature request

Most helpful comment

My 2 cents. In order to get runtime type introspection there are 2 ways:

  • (1) convert a static type to a runtime value representing that type
  • (2) convert a runtime value representing a type to a static type

(1) has been explored in some babel plugins, for example

However (2) seems more reliable. I'm working on a POC of a compatible runtime type system for Flow flow-runtime

See also validated by @andreypopp

The idea is that if you can represent a type T at the value level then you can extract T using the typeof operator in order to lift the value at the type level

import * as t from 'flow-runtime'

type ExtractType<T, RT: Type<T>> = T;
type TypeOf<RT> = ExtractType<*, RT>;

const Person = t.object({
  name: t.string,
  age: t.number
})

// this is equivalent to
// type PersonT = { name: string, age: number };

type PersonT = TypeOf<typeof Person>;

All 5 comments

@gcanti you should take a look at this ;-)

My 2 cents. In order to get runtime type introspection there are 2 ways:

  • (1) convert a static type to a runtime value representing that type
  • (2) convert a runtime value representing a type to a static type

(1) has been explored in some babel plugins, for example

However (2) seems more reliable. I'm working on a POC of a compatible runtime type system for Flow flow-runtime

See also validated by @andreypopp

The idea is that if you can represent a type T at the value level then you can extract T using the typeof operator in order to lift the value at the type level

import * as t from 'flow-runtime'

type ExtractType<T, RT: Type<T>> = T;
type TypeOf<RT> = ExtractType<*, RT>;

const Person = t.object({
  name: t.string,
  age: t.number
})

// this is equivalent to
// type PersonT = { name: string, age: number };

type PersonT = TypeOf<typeof Person>;

This is a very interesting approach. I hadn't seen %checks before. Are there any real limitations to the above?

Are there any real limitations to the above

None that I'm aware of. Theoretically you can't represent at the value level a type which lives only at the type level, for example React$Element. In practice you can always use a cast

import type { Type } from 'flow-runtime'
import * as t from 'flow-runtime'

// at the value level this will be a bit loose...
const ReactElement: Type<React$Element<*>> = t.any // or t.obj

type ExtractType<T, RT: Type<T>> = T;
type TypeOf<RT> = ExtractType<*, RT>;

// ...but flow works as usual
function foo(): TypeOf<typeof ReactElement> {
  return 1 // <= flow complains: number. This type is incompatible with the expected return type of React$Element
}

There are other special types in Flow, namely the "magic types" ($Keys, $Exact, etc...) but I'm working on them.

/cc @ivan-kleshnin

+1 for question.

The only thing which letting me down with runtime-first approach is that syntax of types annotations not that beautiful as in case of Flow or TypeScript.

Was this page helpful?
0 / 5 - 0 ratings