rescript-association / genType

Auto generation of idiomatic bindings between Reason and JavaScript: either vanilla or typed with TypeScript/FlowType.
https://rescript-lang.org/docs/gentype/latest/introduction
MIT License
758 stars 44 forks source link

Generate enum type from polyvar? #518

Closed adnelson closed 10 months ago

adnelson commented 3 years ago

If I have some code like this:

[@genType]
type color = [ | `Red | `Blue ];

then gentype will create a binding like

export type color = 
    "Red"
  | "Blue";

I was looking at the options and I'm not sure if I missed it but is there a way to generate an enum like

export enum color {
  "Red" = "Red",
  "Blue" = "Blue"
};

?

cristianoc commented 3 years ago

@adnelson there are no options to generate enums.

adnelson commented 3 years ago

Would this be desirable? The use case I'm looking at now is the nexus graphql schema library, which can take a JS enum and produce a graphql enum type.

Hypothetically:

[@genType.enum]
type color = [ | `Red | `Blue ];

Or alternatively, via a flag in gentypeconfig like

{
  "gentypeconfig": {
    "variantStyle": "enum"
  }
}

If this is something you might be interested in, I can try my hand at implementing it.

cristianoc commented 3 years ago

@adnelson how about starting by exploring the design, then see how that fits.

A couple of first questions:

adnelson commented 3 years ago

I'll circle back on the design, my initial thoughts regarding your Q's:

export enum MyEnum {
  Foo = "Foo",
  Bar = "BAR",
};

tsc will emit code like this

var MyEnum;
(function (MyEnum) {
    MyEnum["Foo"] = "Foo";
    MyEnum["Bar"] = "BAR";
})(MyEnum || (MyEnum = {}));
;

Which means that at runtime MyEnum.Foo === "Foo".

const myEnumValues = {
  Foo: "Foo",
  Bar: "BAR",
};

type MyEnum = $Keys<typeof myEnumValues>;
cristianoc commented 3 years ago

Looks like in TS a value of enum type also has union type, but not the other way round. Not sure why that is the case if the runtime representation is the same.

cristianoc commented 3 years ago

OK looks like color.Red is nominally typed, so it's a different type than "Red".

cristianoc commented 3 years ago

Poly variants are structurally typed, so mapping them to a nominal type has a few footguns, e.g. you can't rely on type inference. E.g. if you export @genType let red = `Red it won't have type color.

cristianoc commented 3 years ago

@adnelson could you explain the use case with nexus graphql a bit more in detail? And whether there are other use cases.

cristianoc commented 3 years ago

If the use case is worth it, it could be an experimental feature.

cristianoc commented 3 years ago

Happy to continue the convo if there's still interest? Or we can close this otherwise.

ryyppy commented 10 months ago

This repository is being archived. If you feel like the issue still relevant, please re-create it in the compiler repo. Thanks!