This is how #TypeScript enums are hurting your projects 🚨 Ever wonder why seasoned TypeScript pros advise steering clear of enum? While they might seem convenient to define a fixed set of constants, they can cause tricky issues—both in performance and type safety. Let’s break it down: 1. Surprise Code Bloat: When TypeScript compiles enums, it injects additional code into your bundle. That means bigger files, slower load times, and a less efficient app. Not exactly what you signed up for, right? (this issue can be solved by creating constant enums, but they come with their own set of issues). 2. Unsafe Numeric Types (fixed in TS 5.0.4): Numeric enums look neat, but here’s the kicker: TypeScript will happily accept any number you throw at a function expecting an enum. Yikes! That means values outside the defined range can sneak in and wreak havoc. 3. No error on duplicate initializers: If you use the same value for multiple keys of your enum, no error or warning will be thrown. 4. TypeScript is a compile time tool but Enums are runtime values: TypeScript is a compile time tool and its values are removed during build time. But with enums you also get the the JS version of the enum during the build, and because of that you can use it as values and it's not stripped away during the build. This makes enums a runtime construct contradictory to everything else in TS. 5. No consistency between string and Numeric enums: With string enums, only a key value pair is generated for each value. With Numeric enums a key value pair is created both ways, so on entry for the value and one for the key 6. Overly Strict String Enums (PersonallyI don't see this as an issue but many people do): Switching to string enums helps avoid the numeric weirdness, but now you’re locked into a named type. Even a perfectly valid string can’t substitute for the enum’s specific value, limiting flexibility and causing compatibility headaches. A Better Way: Use Objects & Literal Types 💡 Instead of enums, consider using literal object definitions and derived types. It’s safer, more flexible, and easier to maintain. Plus, no mysterious code bloat!
Why would I want to use 'manager'? The point of using the enum (or enum-like structures) would be to have named keys in a relevant group. If I use 'manager' as a string here, and later on I decide that the value should be, for example, 'manager-v1' then I would have to change it in every file where I used it. Using the key instead would be always ideal, in my opinion.
Thanks for sharing. I understand the fact that not using enums would reduce build file size. But I would like to know on the line : grantaccesssafely('manager') Isn't it because we don't want literal values like "manager" in the code why we extract them into enums ?
The most obvious use case would be in a monorepo where several packages use the same "set of keys" for some items. So instead of having 200 places (made up number) in frontend, backend, proxy, maybe even separate DB interface layer, which all check for the same strings as literals, you would use an enum to make sure all packages align and you don't introduce bugs by changing the value in one package but forget in others (or just one - or even in just one function), and code review doesn't catch it. With enums (when proper) there is only a single source of truth. You could also use a shared config file of course, but it's basically just a different syntax for an enum anyway.
This is a source of constant frustration in TS for me. In almost any other language, enum is the right choice. In TS, it is often detrimental with superior options. Well said.
Don't use Enums in Typescript. It's not even up for debate, they are broken and the TS team regrets implementing them.
I stopped using enums in typescript some time ago. Is it just typescript that doesn’t deal with enums very well cause in other languages they seem to be pretty powerful
const X = {} as const is preferred.
Very clearly put :). Thanks for sharing!
Senior Full Stack & Cloud Product Developer | Angular Expert
1wInstead of saying what is bad. The true professional says what is better. What are your thoughts? 1) Use as const with Union Types for most modern applications. It's type-safe, lightweight, and easy to use. const Colors = { RED: 'red', GREEN: 'green', BLUE: 'blue', } as const; type Color = typeof Colors[keyof typeof Colors]; // 'red' | 'green' | 'blue' // Usage const myColor: Color = Colors.RED; 2) Use Union of String Literals for straightforward constants. type Color = 'red' | 'green' | 'blue'; Or another approach?