Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: customized ADT field representation #32

Open
bdkent opened this issue Oct 31, 2019 · 1 comment
Open

feature request: customized ADT field representation #32

bdkent opened this issue Oct 31, 2019 · 1 comment

Comments

@bdkent
Copy link

bdkent commented Oct 31, 2019

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?)

@davegurnell
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants