Const objects really are better than enums, in every way except declaration brevity.<p>They're erasable syntax, so they work in environments that just strip types. Their emit is just what you write without the types. They can be composed in a type-safe way with standard JS operations.<p>You can still write JS docs for values, deprecated the, mark them as internal, etc.<p><pre><code> type ValueOf<T> = T[keyof T];
const Foo = {
/**
* A one digit
* @deprecated
*/
one: '1',
two: '2',
three: '3'
} as const;
type Foo = ValueOf<typeof Foo>;
const Bar = {
blue: 'blue',
} as const;
type Bar = ValueOf<typeof Bar>;
// You can union enum objects:
const FooOrBar = {...Foo, ...Bar};
// And get union of their values:
type FooOrBar = ValueOf<typeof FooOrBar>;
const doSomething = (foo: Foo) => {}
// You can reference values just like enums:
doSomething(Foo.two);
// You can also type-safely reference enum values by their
// key name:
doSomething(Foo['two']);
</code></pre>
Given the TypeScript team's stance on new non-erasable syntax, I have to think this is how they would have gone if they had `as const` from the beginning. Ron Buckton of the TS team is championing an enum proposal for JS: <a href="https://github.com/rbuckton/proposal-enum">https://github.com/rbuckton/proposal-enum</a> Hopefully that goes somewhere and improves the declaration side of thigns too.
Seeing posts like these, I often feel alone preferring enums to string unions.<p>There are certain situations where refactoring a string in a union will not work but refactoring an enum will. I don't want to type strings when, semantically, what I want is a discrete type. I don't even care that they become strings in JS, because I'm using them for the semantic and type benefits, not the benefits that come with the string prototype.
One thing I find useful about enums is that they can be used as both types and values, which is ergonomic for decorator-based libraries (like class-validator, nestjs, mikro-orm, etc). The best approach I've found in union land is using <i>const</i> assertions and <i>typeof</i>, which I don't love.<p>Agree with the author that in almost every other way unions are better though... they play much more nicely with the rest of the type system. I find it endlessly annoying that I have to refer to enum members directly instead of just using literals like you can with union types.
Can anyone explain why enums are somehow bad but literal unions are supposed to be good?<p>I'll be blunt: at the surface level, it looks like literal unions are something that only someone with an irrational axe to grind against enums would ever suggest as a preferable alternative just to not concede that enums are fine.<p>If the problem lies in the low-level implementation details of enums, I cannot see any reason why they shouldn't be implemented the same way as literal unions.<p>So can anyone offer any explanation on why enums should be considered bad but literal unions should be good?
General programming languages theory question, is one supposed to iterate over enum entries or is that considered an antipattern? I have found myself needing to do that a few times and it always felt a bit dirty.
This is my preferred home made way of doing "Enum" in TS theses days <a href="https://gist.github.com/forty/ac392b0413c711eb2d8c628b3e769896" rel="nofollow">https://gist.github.com/forty/ac392b0413c711eb2d8c628b3e7698...</a> - it includes syntax to migrate from TS enum.<p>The member documentation point is a good one, I'll look what can be done with my solution.
What do people find works better as a string enum replacement?<p><pre><code> const Thing {
one: “one”,
two: “two”,
three: “three”
} as const
</code></pre>
Or just<p><pre><code> type Thing = “one” | “two” | “three”
</code></pre>
I’ve been thinking of getting rid of the simple string enums I have but it’s not clear to me why one is preferred over the other by people.
const enums are almost never mentioned by these articles for some reason. They give you the best of both worlds: they're fully erasable, and have good LSP support (do no need to search for strings and bump into false matches — or even worse, for numbers).
The problem with "just use literal strings/numbers" is that that's exactly the <i>opposite</i> of type safe. With them it is impossible to specify an argument of type `myenum | number | string`, despite that being commonly desired in some form.<p>When targeting javascript, it seems to me that the obvious approach is to use <i>symbols</i> for enums. But symbols have a lot of WET.<p>(of course, typescript's safety is unfixably broken in numerous other ways, so why bother?)
> <i>TypeScript 5.8 is out bringing with it the --erasableSyntaxOnly flag</i><p>TypeScript sure loves the "our only documentation lives in the changelog" approach to stuff, huh?<p>- The on-site Algolia search returns 0 results for "erasableSyntaxOnly"<p>- The blocked-from-search release notes[0] looks like actual documentation - but urges to check out the PR[1] "for more information," despite the PR description being essentially blank.<p>- The CLI options page[2] describes it thus: "Do not allow runtime constructs that are not part of ECMAScript," with no links to learn more about what that means.<p>Edit: actually, I take it back! Clicking the flag on the CLI page takes one to an intimidating junk drawer page... but my issues with discoverability stand: <a href="https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly" rel="nofollow">https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly</a><p>[0] <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html#the---erasablesyntaxonly-option" rel="nofollow">https://www.typescriptlang.org/docs/handbook/release-notes/t...</a><p>[1] <a href="https://github.com/microsoft/TypeScript/pull/61011">https://github.com/microsoft/TypeScript/pull/61011</a><p>[2] No idea why on-site search doesn't pick this up: <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html" rel="nofollow">https://www.typescriptlang.org/docs/handbook/compiler-option...</a>