Hacker News new | ask | show | jobs
by demurgos 475 days ago
The solution that you propose is a great relatively-lightweight solution for enums compatible with `erasableSyntaxOnly`. I see also other comments discussing other solutions which are worth comparing.

From my side, I wanted to keep nominal typing and support for lightweight type-level variant syntax (I often use enums as discriminated union tags). Here is what I landed on:

    const Foo: unique symbol = Symbol("Foo");
    const Bar: unique symbol = Symbol("Bar");
    
    const MyEnum = {
      Foo,
      Bar,
    } as const;
    
    declare namespace MyEnum {
      type Foo = typeof MyEnum.Foo;
      type Bar = typeof MyEnum.Bar;
    }
    
    type MyEnum = typeof MyEnum[keyof typeof MyEnum];

    export {MyEnum};
I posted more details in the erasable syntax PR [0].

> This uses `unique symbol` for nominal typing, which requires either a `static readonly` class property or a simple `const`. Using a class prevents you from using `MyEnum` as the union of all variant values, so constants must be used. I then combine it with a type namespace to provide type-level support for `MyEnum.Foo`.

> Obviously, this approach is even more inconvenient at the implementation side, but I find it more convenient on the consumer side. The implementer side complexity is less relevant if using codegen. `Symbol` is also skipped in `JSON.stringify` for both keys and values, so if you rely on it then it won't work and you'd need a branded primitive type if you care about nominal typing. I use schema-guided serialization so it's not an issue for me, but it's worth mentioning.

> The "record of symbols" approach addresses in the original post: you can annotate in the namespace, or the symbol values.

[0]: https://github.com/microsoft/TypeScript/pull/61011#issuecomm...