Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between string enums and string literal types in TS

Tags:

typescript

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.

like image 568
jowey Avatar asked Apr 10 '18 19:04

jowey


People also ask

What is difference between type and enum in TypeScript?

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.

What are string literal types in TypeScript?

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.

Are TypeScript enums strings?

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.

How many types of string literals are there?

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.


4 Answers

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.

like image 117
Ryan Cavanaugh Avatar answered Oct 16 '22 12:10

Ryan Cavanaugh


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.

like image 32
Daniel R Avatar answered Oct 16 '22 10:10

Daniel R


One benefit for an enum at development time is that you will see the list of options easily via intellisense:

enter image description here

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:

enter image description here

like image 20
Frank Modica Avatar answered Oct 16 '22 11:10

Frank Modica


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
like image 3
Andrea Scarafoni Avatar answered Oct 16 '22 11:10

Andrea Scarafoni