Why use Enums
Enums are used to declare literals that are consistent all over your codebase. This enables devs to modify a literal and have it propagated everywhere it's referenced. Since we're not writing a literal by hand we have the benefit of preventing human typos. e.g user
instead of User
Why should we use objects over enums
- Objects are familiar to most developers therefore it's easier to write, read, and use. This pattern is ubiqutous for events based states.
- It reduces load from both Typescript's compiler, and runtime environment.
- Flexible values. Enums values are limited to numbers, strings, and expressions.
- It will work even without Typescript
- Native
Object
andArray
methods can be used
While the reasons above are true. There are downsides to this approach.
Enums from Rust are grossly powerful than what Typescript and other languages offer. I reccommend checking them out. here
Writing Enums with Typescript
For this example we will have roles which we will use to restrict certain roles from accessing certain components.
export enum UserRole {
Admin = "Admin",
SignedUp = "SignedUp",
Guest = "Guest"
}
// Can be used directly as types
type DashboardProps = { allowedRoles: UserRole[] }
// <Dashboard allowedRoles={[ UserRole.Guest, UserRole.SignedUp ]} />
export const userRoles = Object.values(UserRole)
// Warning: This slows down the compiler
const {Admin, SignedUp, Guest} = UserRole
export const Permissions = {
canCreatePosts: [SignedUp, Admin],
canVisitLoginPage: [Guest],
...
}
Rewriting to Javascript objects
export const UserRoleDict = {
Admin: 'Admin',
SignedUp: 'SignedUp',
Guest: 'Guest'
} as const
// Later on, We can have different types of guests. say we want to have a role for the demos of our app. We can refactor our object to nest it under Guest.
export type UserRole = keyof typeof UserRoleDict
type DashboardProps = { allowedRoles: UserRole[] }
// ! We have the option to use the native methods since userRoles is an Array
// <Dashboard allowedRoles={userRoles.filter(user => user !== UserRoleDict.Admin)} />
// <Dashboard allowedRoles={[ UserRoleDict.SignedUp, UserRoleDict.Guest ]} />
export const userRoles = Object.values(UserRoleDict)
const {Admin, SignedUp, Guest} = UserRoleDict
export const Permissions = {
canCreatePosts: [SignedUp,Admin],
canVisitLoginPage: [Guest],
...
}
Conclusion
The tradeoff is clear Objects
allows for more flexibility, and since typescript is not modifying our literals we get predictability. However, Enums
allows for a more concise code sacrificing flexibility.