What are the pros and cons of using as const over enum? Like slight performance advantages, etc.
enum Links {
Link1 = 'test1',
Link2 = 'test2',
}
const Links = {
Link1: 'test1',
Link2: 'test2',
} as const;
What are the pros and cons of using as const over enum? Like slight performance advantages, etc.
enum Links {
Link1 = 'test1',
Link2 = 'test2',
}
const Links = {
Link1: 'test1',
Link2: 'test2',
} as const;
Let's compare string enums to const-asserted object literals with string literal property values!
SUMMARY:
enum brings a named value, a named type, and a named namespace into existence, which needs to be done separately if you want that without an enum.enum is a nominal subtype of string that is not interchangeable with its string literal values.We can dispense with performance first. There is almost certainly no meaningful performance difference between them. Both versions behave the same at runtime: you just have an object named Links with the two properties. And I've never noticed a difference with the compiler either; it's fast either way. If performance is an issue at all, your enums are too big or you have too many of them.
Now for some actually noticeable differences. Note that such differences could be seen as advantages in one situation but disadvantages in another. It really depends on the use case. So let's look at a string enum and see how closely we can approximate it without using an enum:
enum Links {
Link1 = 'test1',
Link2 = 'test2',
}
Declaring Links to be an enum brings a few things into scope:
Links; an object which exists at runtime and has string-valued properties Links.Link1 assignable to "test1" and Links.Link2 assignable to "test2".Links; the union of the possible values of the Links object. As a type it only exists at compile time. For example, you can write interface Foo { link: Links } to mean that a Foo must have a link property which is either Links.Link1 or Links.Link2.Links with exported types named Links.Link1 and Links.Link2, which correspond to the types of the values named Links.Link1 and Links.Link2, respectively. For example, you can write interface Bar extends Foo { link: Links.Link1 } to mean that a Bar must have a link property which is exactly Links.Link1. This sort of thing is handy for building discriminated unions.You can simulate each of these yourself without declaring an enum, and get something which behaves quite similarly (but not identically) to a string enum both at runtime and at compile time:
const Links = {
Link1: 'test1',
Link2: 'test2',
} as const;
type Links = (typeof Links)[keyof typeof Links];
namespace Links {
export type Link1 = typeof Links.Link1;
export type Link2 = typeof Links.Link2;
}
So, one possible advantage to the enum syntax is: if you want to use Links as a value, a type, and as a namespace, this happens automatically; whereas to get the same effect without enum requires quite a bit of boilerplate code. On the other hand, if you don't care about, say, the type or the namespace, you can write const Links = {...} and not bring these unneeded things into existence.
If the above const+type+namespace is not identical to an enum, what's the difference?
The compiler treats an enum as something like a special nominal subtype of string. For the enum, the type of Links.Link1 is assignable to but not from the string literal "test1":
const to: "test1" = Links.Link1; // okay either way
const from: Links.Link1 = "test1"; // error for enum, okay for const
So, if you want Links.Link1 to be completely interchangeable with the string literal "test1", then you should stay away from enum. On the other hand, if you want to enforce that the only way to get that "test1" value is by writing out Links.Link1, you should use an enum.
That means the ideal use for a string enum is one in which the values are mostly treated as opaque. If the user of an enum actually cares about its particular string literal values, it's an indication that you might not really want an enum. For example, imagine I changed the Links definition to this:
enum Links {
Link1 = '454353',
Link2 = 'xxxyyyzzz',
}
If the rest of my code is happy with that change, it's because I only ever refer to the enum values by indexing into Links. Any code that mentions "test2" directly would break, but code that mentions Links.Links2 would continue to work.
Don't know the performance it depends upon how you use it like bubble sort in some conditions and in other conditions insertion sort. You should use enums where data are inter-related with each other like typeOfUsers for login are
enum typeOfUser{
owner='ower',
employee='employee',
admin='admin'
}
Where as const can be used for values which don't needed to be changed and if you want to apply same code as enum mentioned above you can do something like this.
export const typeOfUsers = ['employee', 'owner', 'admin'] as const;
export type typeOfUser = typeof typeOfUsers[number];
Enums restrict you to the necessary set of inputs, while constant strings allow you to use strings that aren't part of your logic. This ensures that you don't make a mistake by entering something that isn't in the domain when entering data, and it also improves the readability of the code.