const MyTypeValues = ['a', 'b'] as const;
type MyType = typeof MyTypeValues[number];
MyType is now a type 'a' | 'b'Not to mention, there's a slight mental overhead to parsing this. When I see this code, I might wonder if there's a reason for this to be an array. I might wonder if the order is intentional.
An enum has a more clear intent. My only complaint is that enums are not string-by-default, so we end up writing our variants twice:
enum MyType {
A = 'a',
B = 'b',
}To be clear, the enum is also defined at runtime. So this specifically isn't a difference.
Some people will argue a preference for string literal union types over enums because the string literal types don't have any runtime overhead. They just provide type safety at write-time and are bare strings at runtime. But as soon as you start adding arrays and custom type predicate functions to work with them, you're adding runtime objects, which removes that particular advantage over enums.
Substantially. Look at the generated code for an enum.
Also, this approach does not suffer the problems described by the article.
I'll give you that. It looks like the TS compiler (according to the playground site) spits out some code that's intended for maximum compatibility with older versions of JS, even when targeting newer versions (which makes sense, since nothing is technically wrong about it).
It spits out:
"use strict";
var MyType;
(function (MyType) {
MyType["A"] = "a";
MyType["B"] = "b";
})(MyType || (MyType = {}));
when, we would obviously write the following in modern JS: "use strict";
const MyType = {
A: "a",
B: "b",
};
So that's a bit disappointing.So, this could matter if you intend to actually read the emitted JS. If, however, you're TypeScript-only, this is more-or-less the same as reading the ASM spit out by your C compiler or the Java bytecode spit out by javac.
> Also, this approach does not suffer the problems described by the article.
This argument doesn't hold water, unless you're taking a philosophical stance. The argument is that most TypeScript features don't actually spit out JavaScript code and this one does.
But, if you're going to write an array that lists your variants (and then write code elsewhere to check if a string is contained by said array, etc), then "extra" JavaScript code is still being generated- it's just generated by you instead of the TypeScript compiler. Why should we care who generates the code?
This argument only works when we're comparing to writing a string literal union type and no other supporting code for that type. My comment was specifically addressing the case of writing an array to hold our literals instead of writing an enum, and I stand by my claim that an enum is better because it's the same runtime overhead, but more clearly communicates intent/semantics to your fellow TypeScript devs (including future-you).
I had always used enums in TS until this year, but union literals are better.
I create my own enums with const objects, compute the type based off the object's values. So very similar this, just with an object as the source instead of an array.
Am I missing something in how to use this?