davegurnell/bridges

feature request: customized ADT field representation

Opened this issue · 1 comments

Have you considered allowing for customization of the ADT's generated type?

It seems currently (at least for the Typescript implementation), that ADTs end up with a hard-coded { type: <constructor name> }.

I would like to be able to:

  • customize the field name for what is currently hard-coded to "type"
  • supply a custom means for the ultimate value of the type field. Perhaps a function from (constructorName, typeName) => string.

If you think this is useful, I can take a stab at pull request. (I assume these options could be easily added to TsEncoderConfig?)

Sorry it's taken me so long to reply to this. I think this is a good idea.

I've been toying with this kind of thing in a couple of commercial projects. When I write discriminated unions by hand in Typescript, I typically do:

interface A {
  type: "A";
  field: number;
}

interface B {
  type: "B";
  field: string;
}

type U = A | B;

whereas Bridges generates:

interface A {
  field: number;
}

interface B {
  field: string;
}

type U =  { type: "A", field: number } | { type: "B", field: string };

These styles of definition have slightly different semantics (are the discriminators always required, or just when U is used?

It'd be nice to be able to swap between these definition styles. Also there's a third option that might be handy:

interface A {
  field: number;
}

interface B {
  field: string;
}

type U =  ({ type: "A" } & A) | ({ type: "B" } & B);

I guess there are two axes in the design space:

  • Do we generate product types as having discriminator fields? Or do we only do that on sum types?
  • Do sum types reference product types or inline their definitions?

I'm guessing it'd be useful to define default semantics for these and override them on a definition-by-definition basis, possibly by wrapping TsDecl in a case class providing the metadata:

  • TsRenderer.render(...) takes an instance of AnnotatedTsDecl that combines a TsDecl with metadata controlling the rendering

  • There's some kind of automatic conversion from TsDecl to AnnotatedTsDecl that pulls the metadata from implicit scope