Unfortunately, neither (string) enums nor string literal unions are supersets of each other when it comes to functionality. But, IMO, string-only enums are generally better.
You can't test if a given string is an element of a union without writing a custom helper and/or allocating a runtime array of the values.
On the other hand, if you don't need to test unknown strings, then union types disappear at compile time, whereas enums are compiled to real, runtime, objects.
Enums don't look like naked strings in the code. Frankly, it's just nicer on my brain to see `return Color.Red` than `return "red"` and wonder if "red" is just some random text or if it has semantic meaning. Hopefully your IDE is smart enough to take you to where "red" is defined as part of a union type when you want to see other options. Granted- the most popular editors ARE smart enough to do that, but that doesn't help when just reading code with my eyes instead of my hands, or in patches/diffs.
In some cases you can use it to define string arguments to an external library. Maybe table names to an ORM or a well-known file path. This helps because you get autocomplete from typing `MyEnum.` and seeing options, even though the external function takes a plain string.
It's not possible to get the autocomplete unless the function/method you're calling takes a union. Many libraries can't do that because they need to be flexible in what they receive. So yeah, you can define a union, but editors don't have the context to know your union applies to the call.
If you have to change one of the underlying values, you only need to change it in one place. Of course, you could just use constants, but then you’ll just have a const enum with extra steps.
You can't test if a given string is an element of a union without writing a custom helper and/or allocating a runtime array of the values.
On the other hand, if you don't need to test unknown strings, then union types disappear at compile time, whereas enums are compiled to real, runtime, objects.
Enums don't look like naked strings in the code. Frankly, it's just nicer on my brain to see `return Color.Red` than `return "red"` and wonder if "red" is just some random text or if it has semantic meaning. Hopefully your IDE is smart enough to take you to where "red" is defined as part of a union type when you want to see other options. Granted- the most popular editors ARE smart enough to do that, but that doesn't help when just reading code with my eyes instead of my hands, or in patches/diffs.