mojotech / json-type-validation

TypeScript JSON type validation
MIT License
155 stars 14 forks source link

Provide script that can rewrite TS interfaces to object({}) #30

Closed joshua-holly89 closed 5 years ago

mulias commented 5 years ago

Hi @joshinator, this is a feature I've definitely thought about in the past, although in a slightly different context. If it's something that you'd be interested in implementing I would be happy to review your PR. I know that Typescript's internal tools provide some mechanisms for programmatically parsing and building code, so that would probably be a place to start.

If you've been trying out this library and really don't like defining both types and decoders, then I have two pieces of advice:

  1. Try out https://github.com/pelotom/runtypes instead. It's a similar library, but it does a few things differently. Specifically, it suggests that you only define "runtypes" which are what I've called decoders. You then derive your static types off of your runtypes:
    
    const Asteroid = Record({
    type: Literal('asteroid'),
    location: Vector,
    mass: Number,
    });

type Asteroid = Static;

It's a pretty clever strategy. My one issue with it is that in a lot of cases the type you use in your application and the type you need to validate from outside your application _should be_ different types. But if the one-to-one mapping is what you want then that's what I'd look at.

2. If you want to stick with this library, you can try implementing the `Static` type like this:

type Static = D extends Decoder ? U : never;

const asteroidDecoder = object({ type: constant('asteroid'), location: vectorDecoder, mass: number(), });

type Asteroid = Static;


The last time I experimented with deriving the static type I found that it was a little rough around the edges, but it might be enough for your needs.
joshua-holly89 commented 5 years ago

Hello @mulias ,

Thank you for your detailed answer to my short suggestion :) Its a very interesting approach. As far as I understand, you would define an object that you can use at runtime and at the same time "extract" its type. I'm just afraid that the types will then not be as easy to read as if you'd just define them in the plain normal way...

I think your library is already good, because you cant really make a mistake when creating the object because its type safe. It just took me super long, that's why I was thinking of a script. The DRY-principle violation is not that bad imho.

Because I think you are forced by the TS-compiler to adjust the object whenever the type changes (also for optional fields)?

mulias commented 5 years ago

Now that TS 3.4 has fixed higher order type inference I think that the Static should work more consistently. At some point in the future I (or someone reading this) should figure out how to implement dtslint for type-level testing and verify that deriving a type from a decoder consistently produces the right result. If that's the case then I think it's appropriate to add the type utility to the library.

That said, I ultimately agree that decoders are harder to read than types, so deriving types off of decoders could lead to confusion.