ForbesLindesay / funtypes

Runtime validation for static types
MIT License
29 stars 4 forks source link

Create a babel macro #30

Open ForbesLindesay opened 4 years ago

ForbesLindesay commented 4 years ago

See: https://github.com/pelotom/runtypes/issues/128

It should be fairly doable for types defined in the same file. We could potentially allow it to work for types defined in other files, providing that they are explicitly re-exported using the macro.

vedantroy commented 4 years ago

Just saw this -- quick word of advice, files that span multiple types are hard to implement (maybe do-able?) due to the fact that Babel processes files 1 at a time:

https://github.com/kentcdodds/babel-plugin-macros/issues/155

ForbesLindesay commented 4 years ago

The idea behind this would be that you could do something like:

File A

import runtime from 'funtypes.macro';

export interface MyType {
  someKey: string
}
export const MyType = runtime<MyType>()

File B

import runtime from 'funtypes.macro';

import {MyType} from './FileA'

export interface MyOuterTypeType {
  outerKey: MyType
}
export const MyOuterTypeType = runtime<MyOuterTypeType>()

The generated code would then look like

File A

import * as ft from 'funtypes'

export const MyType = ft.Object({someKey: ft.String})

File B

import * as ft from 'funtypes'

import {MyType} from './FileA'

export const MyOuterTypeType = ft.Object({outerKey: MyType})

We would still only be processing one file at a time, we just rely on any imported type having an imported Funtype validator of the same name.

ForbesLindesay commented 4 years ago

We could allow this to be checked at compile time by having FileB become:

import runtime from 'funtypes.macro';

import {MyType} from './FileA'

export interface MyOuterTypeType {
  outerKey: MyType
}
export const MyOuterTypeType = runtime<MyOuterTypeType>(MyType)

Where the type definition of runtime would be:

function runtime<T>(...children: Runtype<T>[]): Runtype<T>

The babel macro could then error if there were any imported types that were not passed as arguments. TypeScript would check that the values you pass in are Runtypes.