Assuming I want to ensure that myKey
in { myKey: '' }
only contains the strings foo
, bar
, baz
, I could achieve this in two ways.
// with a String Literal Type
type MyKeyType = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
I wonder where the pros and cons of one over the other are, as both look the same to me (exept from the way I would access the values for e.g. a condition check).
The only difference I found in the TS documentation is that Enums are real objects at runtime, what might be desirable in some cases.
Enums allow us to define or declare a collection of related values that can be numbers or strings as a set of named constants. Unlike some of the types available in TypeScript, enums are preprocessed and are not tested at compile time or runtime.
The string literal type allows you to specify a set of possible string values for a variable, only those string values can be assigned to a variable. TypeScript throws a compile-time error if one tries to assign a value to the variable that isn't defined by the string literal type.
Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.
There are three sets of literal types available in TypeScript today: strings, numbers, and booleans; by using literal types you can allow an exact value which a string, number, or boolean must have.
The key thing to understand is that the values of string enums are opaque.
The intended use case for a string enum is that you don't want other code to know or care what the literal string backing MyKeyType.FOO
is. This means that you won't be able to, say, pass the literal string "bar"
to a function accepting a MyKeyType
-- you'll have to write MyKeyType.BAR
instead.
Well, there is a difference between string enums and literal types in the transpiled code.
Compare the Typescript Code
// with a String Literal Type
type MyKeyType1 = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType2 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
With the transpiled JavaScript Code
// or with a String Enum
var MyKeyType2;
(function (MyKeyType2) {
MyKeyType2["FOO"] = "foo";
MyKeyType2["BAR"] = "bar";
MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
What you can see is, there is no generated code for the string literal. Because Typescripts Transpiler is only using for type safety while transpiling. At runtime string literals are "generated to dumb" strings. No references between the definition of the literal and the usages.
So there is a third alternative called const enum
Look at this
// with a String Literal Type
type MyKeyType1 = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType2 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
// or with a Const String Enum
const enum MyKeyType3 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
var a : MyKeyType1 = "bar"
var b: MyKeyType2 = MyKeyType2.BAR
var c: MyKeyType3 = MyKeyType3.BAR
will be transpiled to
// or with a String Enum
var MyKeyType2;
(function (MyKeyType2) {
MyKeyType2["FOO"] = "foo";
MyKeyType2["BAR"] = "bar";
MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
var a = "bar";
var b = MyKeyType2.BAR;
var c = "bar" /* BAR */;
For further playing you can check this link
I prefer the const enum case, because of the convenient way of typing Enum.Value. Typescript will do the rest for me to get the highest performance when transpiling.
One benefit for an enum at development time is that you will see the list of options easily via intellisense:
Similarly, you could change an enum value easily using refactoring tools, instead of changing a string everywhere.
Edit: In VS 2017 and TypeScript >=3.2.4, intellisense works with string literal types:
A big downside of enum is that if you use number instead of string, the entirely enum is not safety in my opinion: i can always assign any number value to a variable of this kind
enum TYPE {MAN = 1, WOMAN = 2, BOY = 3, GIRL = 4};
let foo: TYPE = TYPE.MAN;
foo = 37.14; //no problem for compiler
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With