Three months ago, I submitted what I thought was a perfectly reasonable pull request. I had created a new UserRole enum to handle our permission sy...
For further actions, you may consider blocking this person and/or reporting abuse
Haha
Ive a funny story about enums
While learning TS, as all suggest "see TS compiled code into JS" to see how and what it compiled to.
And as beginner curiosity I also did that at that time, and seeing TS code into JS, I was said everything TS related things will be reversed like types, etc. And it was true every TS annotations were not in compiled JS.
Then I learnt about enums and when it converted to JS, I did not expected that, was seeing an IIFE function, all I knew that time was TS should convert it to be in compiled time thing but IIFE funcs are runtime, and also couldnt comprehend how things were "working" in that function, so just for "i did not understand working of that thing" i switched the road and took "objects as const" and put "enums" on sideways as future topic but from then ive never needed to use enums
I still find this funny, a simple not understanding of working of enums from TS to JS transfered me to whole new path
It's funny how, as we progress in our careers, we always encounter uncharted territory within JavaScript/TypeScript's complex abstractions. At first it feels discouraging - until you consider how JavaScript enabled over a billion web and mobile projects that would otherwise never exist. Then you implement that fix, wake up the next morning, and suddenly everything feels right with the world again. ✨
Thanks for all the details!
Fantastic deep dive and a crucial lesson for many TypeScript developers! The const object with as const pattern is undeniably superior for the reasons you've outlined.
I'm definitely making a point of using the pattern going forward: it ensures stricter literal typing and solves the tree-shaking problem completely. That side-by-side comparison of Numeric Enum Nightmare and the const object solution is perfect.
this hits hard - especially the reverse mapping discovery. i had the exact same moment looking at compiled output and going "wait, why are we shipping TWO mappings for every numeric enum?"
the const enum trap is even more subtle though. you think you're being smart by using
const enumto avoid the runtime code, but then you ship a library and suddenly your consumers can't use it because the values get inlined at compile time. breaks module boundaries in ways that aren't obvious until production.one thing i'd add: the migration path matters. when you have 50+ enum usages across a codebase, switching to
as constobjects means updating every. single. reference. because the access pattern changes fromStatus.Activeto staying the same BUT the type inference is different.we ended up with a hybrid during migration: new code uses union types, legacy enums stay but with explicit
// TODO: migratecomments. not perfect but beats a 3-day refactor that blocks feature work.also the tree-shaking point is huge for libraries. we saved 2KB on our SDK bundle just by killing numeric enums. that's real bytes users download.
The catch here is amazing
Nice post,actually i have used enum many times,never considered what it will translated to js,great,i will change it to cost,thx
Thanks for the super in-depth write up! I recently came to this understanding too and this is such a great resource if a discussion about enums ever comes up, and I need to make my case.
I don't agree. If you write enums like that I'd be asking you to change them back. You are trying to be clever by creating your own types rather than using the language as designed just to save a few kb at best. The typescript compiler can always be improved in the future to generate cleaner javascript, but if you write your code in a non standard format like this not only is the code less succinct but you miss out on those future updates to the compiler.
Did not expect this to be so in depth. Do you think TypeScript enums themselves could/should be improved to prevent having to manually convert all of these (ex. some sort of flag/parameter/keyword for numeric enums that makes their use cases stricter)?
To me better DX is worth the extra 12 KB. That kind of saving is negligible it’s like over-engineering with floats just to support the last % of IE users.
Namespaces are fantastic if you have a big codebase and only use it for grouping types.
export declare namespace User {
interface Dto { id: string }
}
Then you can simply import {User} and use User.Dto. Instead of having to pollute your intellisense with a million types.
As long as you do it like this there are no downsides since the types are simply erased, so no issues with compilers, esmodules or tsconfig flags.
Eye-opening breakdown enums always felt off, but seeing the compiled output makes it undeniable. Love the const object + as const approach cleaner, safer and more JS-native.