TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

TypeScript enums: use cases and alternatives

177 pointsby mariuz4 months ago

21 comments

skrebbel4 months ago
One thing I&#x27;m missing in the comments here is that enums are a very early TypeScript feature. They were in there nearly from the start, when the project was still trying to find clarity on its goals and principles.<p>Since then:<p>- TypeScript added string literals and unions, eg `type Status = &quot;Active&quot; | &quot;Inactive&quot;`<p>- TypeScript added `as const`, eg `const Status = { Active: 0, Inactive: 1 } as const`<p>- TypeScript adopted a stance that features should only generate runtime code when it&#x27;s on a standards track<p>Enums made some sense back when TS didn&#x27;t have any of these. They don&#x27;t really make a lot of sense now. I think they&#x27;re effectively deprecated, to the point that I wonder why they don&#x27;t document them as deprecated.
评论 #42767746 未加载
评论 #42768690 未加载
评论 #42768367 未加载
评论 #42767743 未加载
评论 #42769638 未加载
msoad4 months ago
After almost a decade of TypeScript my recommendation is to not use TypeScript enums.<p>Enums is going to make your TypeScript code not work in a future where TypeScript code can be run with Node.js or in browser when typings are added to JavaScript[1]<p>Enums results in runtime code and in most cases you really want type enums. Use `type State = &quot;Active&quot; | &quot;Inactive&quot;` and so on instead. And if you really want an closed-ended object use `const State = { Active: 1, Inactive: 0 } as const`<p>All of the examples in the article can be achieved without enums. See <a href="https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play&#x2F;?#code&#x2F;PTAEFEA8EMFsAcA2BTUBGAXKAqgZwJYB2A5qAK6H4D2hoALgJ7zK6hG53LQAmoVAZqGSEysXAChGzUAGU60TqAC8oAEQBBAMZ18AN2SrQAHzUBJQtG16DAbnHj+FKzVCIqxOQuQAKDl6yenACUoADe4qCRoJo0uFQoAHRuxN4ABgAqABaommQATnnCdKB+ivi4WAAkoaXIAL6pQXZ19iA4uNDEyOLJgT4aVvqqTT3ufd6qAArC3ETEwzagbeAFVHlY6UyoAORTM3Oq22yshFTF0LgExBYARij0VPRboNt92wmtYFBwSKgATFg8HNQNBorF5IRilQbgArZDaUAAd3wdEyoFSFzBhA4qXEMWxxT6yjCESiWh0+iwAwpBgANKTIuZLDSqUzBnTxHUQax8Rw7JJnn0ANLIBisFQAa1FAiezBlfUWbWp1kMJlUbJpqgF0j6ADVoIgyCxid4pMh5fJggBtYWi3AAXUVYGVQ2MZgs7K1DicOhcvUtyAAYnkqLAAPKw+F0XwBgIB-WGlghcJRLFxRLJNJZHL5QqQkoB45VGoBhojFriNp4Trdf1eYOhiNw7TePoJcnWEZ1zgN8ORlt7QizEgLJZfVbrUCbaS7aZDg5HcqgU7nS74a7QO6oOiPM0vF0GN3qj2a96fCAwBD3ADMWAAcqJkHl8JohCJYKBCkhLMhYEU8eCoAPn+z6aESKgpmS7JYGg9Kphq1hYAADPSXKYrydD8nuwFPi+eoGka4qgKaWwyjhoF9EEVpSgwMpmmRj4UQGjpjugbpIfYjiEM4tDJOReEBjG-hAYxAleAmhHJgyabxMgSTuFm2TLqJr61EWoDVLUZbNOe1ZdKMxD8WBglGW2Hb6F27imYJfxNKxKwhpO047H8i4nGc3JXLc9w7rKOxIW6aBnpWXyXr8oAACxYAAstA8DwMC764a+awFs+JCgLoBHGr5mSiNAhAALSFDwm73BYf4SBh7RPgASrJxKQZE6jcLARBUuoAAi0WmHeqhwVEeBPlS2AyOAtX9dJADihF0FSU3YOAMjpJNaE8uCWHPENeT1SgEnGioJFyoI227cgVE0XRpEnbgdWySxSpdT1fVHqN42qmoC1LStnE+tQtBdHQp2yd4IYoICt07bJ+24FJqa4MidCaGioOyXDqZRJoFyoMDiQtW1hAYNJGNRIUdD5LQGitUQ5R0HkChrKodgk5EWO3TVUOJNtRMsxjZMU2onhDtAeS8NtTPE5j2Mc2dCQzSwc2SyT-N5JT8scBzEupi0FZVh0+m8rJ8kpIDuM+Gb7bU4QQR2W0+M0xw9M7nkAHYkbmam5DZ0TGGADqd7vTbToQBOGzPLsfsBxNbnLh5FxeWV267uHGjdb1H2qG9E1Hl9y2HB8IUXj89wAKxYJ1DAVS+oA0awZAEBlqSXfwqQgkOfklNA-DIIwrsawAwvEayxfAjXSbVyDcFSADEgaBkhC9IZNqZTYUwgzwvc8L8vUQAEKJhvi9z6t3Jpph9h7oPbh5ERzd+TKV-D3FweqBP3AZ6vyDCBn+9Gl6XE8VAIDR+eQAASyBIDeBiNfLAIDYYklTCrWgICR5WmgWsR0nJdL626IbDMClgFDzARAiYb9hi2zALPeei8+7uwIT3EB4DIGqAAJrIEQG4RE5Dg4OTWGHGcrD2GcMOMcWOq4E5bgeB3XYZCc5r0ID-RM+dxBAA" rel="nofollow">https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play&#x2F;?#code&#x2F;PTAEFEA8EMFsAcA2B...</a><p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-type-annotations">https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-type-annotations</a>
评论 #42770151 未加载
评论 #42767840 未加载
评论 #42768771 未加载
评论 #42767593 未加载
评论 #42767313 未加载
评论 #42767097 未加载
评论 #42767312 未加载
评论 #42767346 未加载
评论 #42768034 未加载
评论 #42767353 未加载
评论 #42767066 未加载
ivanjermakov4 months ago
I use TypeScript in a way that leaves no TS traces in compiled JS. It means no enums, no namespaces, no private properties, etc.<p>Great list of such features: <a href="https:&#x2F;&#x2F;www.totaltypescript.com&#x2F;books&#x2F;total-typescript-essentials&#x2F;typescript-only-features" rel="nofollow">https:&#x2F;&#x2F;www.totaltypescript.com&#x2F;books&#x2F;total-typescript-essen...</a><p>TS has a great type system, the rest of the language is runtime overhead.
评论 #42767828 未加载
conaclos4 months ago
The suggested alternative looks overly complex to me. Moreover, it uses the `__proto__` property that is deprecated [0] and never was standardized. I could write something like this instead:<p><pre><code> type MyEnum = typeof MyEnum[keyof typeof MyEnum]; const MyEnum = { A: 0, B: 1, } as const; </code></pre> Unfortunately I found it still more verbose and less intuitive than:<p><pre><code> enum MyEnum { A = 0, B = 1, } </code></pre> TypeScript enum are also more type-safe than regular union types because they are &quot;nominally typed&quot;: values from one enum are not assignable to a variable with a distinct enum type.<p>This is why I&#x27;m still using TypeScript enum, even if I really dislike the generated code and the provided features (enum extensions, value bindings `MyEnum[0] == 0`).<p>Also, some bundlers such as ESbuil are able to inline some TypeScript enum. This makes TypeScript enum superior on this regard.<p>In a parallel world, I could like the latter to be a syntaxic sugar to the former. There were some discussions [1] for adopting a new syntax like:<p><pre><code> const MyEnum = { A: 0, A: 1, } as enum; </code></pre> [0] <a href="https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&#x2F;Reference&#x2F;Global_Objects&#x2F;Object&#x2F;proto" rel="nofollow">https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&#x2F;Refe...</a><p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;TypeScript&#x2F;issues&#x2F;59658">https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;TypeScript&#x2F;issues&#x2F;59658</a>
评论 #42768187 未加载
Aeolun4 months ago
I don’t understand all these comments. I use TS enums like I use Java enums and I literally never have issues. What are y’all doing with these?
评论 #42770810 未加载
评论 #42771648 未加载
评论 #42772449 未加载
评论 #42769731 未加载
评论 #42768737 未加载
评论 #42769951 未加载
joshstrange4 months ago
We alway use this in place of ENUMs:<p><pre><code> export const SMS_TYPE = { BULK: &#x27;bulk&#x27;, MARKETING: &#x27;marketing&#x27;, PIN: &#x27;pin&#x27;, SIGNUP: &#x27;signup&#x27;, TRANSACTION: &#x27;transaction&#x27;, TEST: &#x27;test&#x27;, } as const; export type SmsType = typeof SMS_TYPE[keyof typeof SMS_TYPE]; </code></pre> ENUMs (at least in my experience, which may be dated) had a number of drawbacks that pushed us to this format. I vaguely remember having issues parsing data from the server and&#x2F;or sending ENUM values to the server but it&#x27;s been a long time and I&#x27;ve been using this const pattern for around 5 years or so now.
评论 #42771172 未加载
评论 #42772246 未加载
bluelightning2k4 months ago
I personally see TS enums as an anti-pattern.<p>One big reason: you can&#x27;t name it interfaces.d.ts, or import as type, which has widespread implications:<p>Your types are now affecting your shipped bundles.<p>Sure that&#x27;s a small bit of size - but it can actually lead to things like server side code getting shipped to the client.<p>Whereas if it&#x27;s all .d.ts stuff you know there&#x27;s no risk of chained dependencies.<p>I&#x27;d go so far as to say default eslint rules should disallow enums.
评论 #42767130 未加载
estsauver4 months ago
I like how this article demystifies TypeScript enums—especially around numeric vs. string values and all the weird runtime quirks. Personally, I mostly steer clear of numeric enums because of that dual key&#x2F;value mapping, which can be as confusing as Scala’s old-school Enumeration type (where numeric IDs can shift if you reorder entries). In Scala, it’s often better to use sealed traits and case objects for exhaustiveness checks and more explicit naming—kind of like TS’s union-of-literal types.<p>If you just need a fixed set of constants, union types with never-based exhaustiveness checks feel simpler and more “ADT–style.” That approach avoids generating the extra JS code of enums and plays nicer with certain “strip-only” TypeScript setups. In other words, if you’ve ever regretted using Enumeration in Scala because pattern matching turned messy or IDs moved around, then you’ll probably want to keep TypeScript enums at arm’s length too—or at least stick to string enums for clarity.
chpatrick4 months ago
I think type-level string unions are the way to go. They&#x27;re concise, efficient (the strings are interned anyway), and when you&#x27;re debugging you know what the values are rather than getting mysterious integers.
评论 #42783950 未加载
rednafi4 months ago
For someone who writes TS only occasionally and mostly doesn&#x27;t care about the JS ecosystem, this is a great article. I picked up a few tricks. That said, normalization of warts is a common thing in JS, and people tend to just live with it rather than fix it. This feels like another example of that.<p>In Go, if something is discouraged (unsafe, runtime, reflection shenanigans), you immediately know why. The language is mostly free of things that exist but you shouldn’t use.<p>TS was a breath of fresh air when it came out. I never took Node seriously for backend work—it was always something I reluctantly touched for client-side stuff. But TS made some of JS’s warts bearable. Over time, though, it’s added so many crufts and features that these days, I shudder at the thought of reading a TS expert’s type sludge.
评论 #42768862 未加载
评论 #42767318 未加载
OscarDC4 months ago
A particularly ugly but useful feature of &quot;const enum&quot; (sadly, the &quot;const&quot; flavor of enums are not referred to in this documentation), is that it&#x27;s the only way to declare a compile-time constant in TypeScript.<p>e.g. for &quot;development&quot; vs &quot;production&quot; environments, you could write a declaration file for each of those envs as such:<p><pre><code> &#x2F;&#x2F; production.d.ts declare const enum ENVIRONMENT { PROD = 0, DEV = 1, CURRENT_ENV = PROD, } </code></pre> And then write in your code something like:<p><pre><code> &#x2F;&#x2F; some_file.ts if (ENVIRONMENT.CURRENT_ENV === ENVIRONMENT.DEV) { &#x2F;&#x2F; do something for dev builds } </code></pre> It will be replaced by TypeScript at compile-time and most minifiers will then be able to remove the corresponding now-dead code when not in the right env.<p>This is however mainly useful when you&#x27;re a library developer, as you may not have any &quot;bundler&quot; dependency or any such complex tool able to do that task.<p>Here, the alternative of bringing a complex dependency just to be able to replace some constants is not worth its cost (in terms of maintenance, security, simplicity etc.), so even if `const enum`s may seem poorly-adapted, they are actually a good enough solution which just works.
Blackarea4 months ago
Ts enums are unofficially deprecated.<p>I remember being shocked about it when i heard that on ts-congress by, Nathan Sanders a ts contributor, around 4-5 years ago.<p>I find the ts-enums incredibly poorly designed and advice my juniors to stay away from them generally.<p>It&#x27;s almost similar for interface (<a href="https:&#x2F;&#x2F;shively-sanders.com&#x2F;types-vs-interfaces.html" rel="nofollow">https:&#x2F;&#x2F;shively-sanders.com&#x2F;types-vs-interfaces.html</a>)
MortyWaves4 months ago
Had a quick look but I was surprised to see using a Set.<p>Personally I use a plain string union. If I need to lookup a value based on that I’ll usually create a record (which is just a stricter object). Typescript will error if I tried to add a duplicate.<p>This is all enforced at build time, whereas using a Set only happens at runtime.<p><pre><code> type Fruit = ‘apple’ | ‘banana’; const lookup: Record&lt;Fruit, string&gt; = { ‘apple’: ‘OK’, ‘banana’: ‘Meh’ } </code></pre> Unions are a more more universal syntax than enums.<p>It isn’t forced to be a 1:1 map of string to string; I’ll often use string to React components which is really nice for lots of conditional rendering.<p>On a slightly related topic, I also feel that the ‘type’ keyword is far more useful and preferable than ‘interface’. [1]<p>[1]: <a href="https:&#x2F;&#x2F;www.lloydatkinson.net&#x2F;posts&#x2F;2023&#x2F;favour-typescript-types-over-interfaces&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.lloydatkinson.net&#x2F;posts&#x2F;2023&#x2F;favour-typescript-t...</a>
评论 #42771500 未加载
mceachen4 months ago
I&#x27;ve found this to be quite ergonomic and functional for handling string enumerations (including completeness in switches and record definitions):<p><a href="https:&#x2F;&#x2F;github.com&#x2F;photostructure&#x2F;fs-metadata&#x2F;blob&#x2F;main&#x2F;src&#x2F;string_enum.ts">https:&#x2F;&#x2F;github.com&#x2F;photostructure&#x2F;fs-metadata&#x2F;blob&#x2F;main&#x2F;src&#x2F;...</a><p>Usage:<p><pre><code> export const Directions = stringEnum(&quot;North&quot;, &quot;South&quot;, &quot;East&quot;, &quot;West&quot;) export type Direction = StringEnumKeys&lt;typeof Directions&gt; </code></pre> (I haven&#x27;t published this as a discrete npm package--IMHO you should copy and paste this sort of thing into your own tree).
forty4 months ago
After several iterations (some of which older than TS native enums if I remember well), this is the Enum code I ended up with. It creates type, &quot;accessors&quot; (`MyEnum.value`), type guard (`isMyENum(...)`) and set of values (`for(const value of MyEnum)`), and have 2 constructor to allow easier transition from TS native enum.<p><a href="https:&#x2F;&#x2F;gist.github.com&#x2F;forty&#x2F;ac392b0413c711eb2d8c628b3e769896" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;forty&#x2F;ac392b0413c711eb2d8c628b3e7698...</a>
nick_wolf4 months ago
This article could be an unintentional case study in why letting patterns emerge beats designing them upfront. Java devs insisted on enum classes while JS devs gravitated towards plain objects tells us something about language evolution.<p>Makes me wonder if it was a mistake to include them at all instead of letting the community converge on patterns naturally, like we did with so many other JS patterns.
评论 #42770950 未加载
wildpeaks4 months ago
I&#x27;d advise against using TS enums nowadays because they conflict with a few useful flags (such as &quot;isolatedModule&quot; or Node type stripping).<p>A good tsconfig: <a href="https:&#x2F;&#x2F;gist.github.com&#x2F;cecilemuller&#x2F;80fed1b963171ca4e117f6d1e2a4a5a7" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;cecilemuller&#x2F;80fed1b963171ca4e117f6d...</a>
bryancoxwell4 months ago
Are there any TS types aside from enums that generate runtime code?
评论 #42770998 未加载
harha_4 months ago
TypeScript is unnecessarily complex.
评论 #42771436 未加载
jffuwaaaasdf4 months ago
enums and namespaces were two mistakes in the early days of typescript.
shepherdjerred4 months ago
I dislike TypeScript enums for two reasons:<p>1. They have a runtime representation unlike most of the rest of TypeScript<p>2. They follow nominal typing instead of structural typing, again unlike the rest of TypeScript<p>IMO it&#x27;s best to use string union types instead of enums. If you need to map that to another representation you can use a function or a record.
评论 #42771242 未加载