Enums

Enums are a useful entity intended for holding a specific value that is referenced using a friendly name to keep code readable. An enum value is nothing more than an integer that is associated with a named constant. Enums are very simple to declare, however, it is what they generate in JavaScript that makes them interesting. First, let's look at an enum declaration and then we will go over the result:

enum ShapeType {
    Rectangle,
    Circle,
    Line,
    Freehand   
}

The declaration of an enum type takes the type name for referencing the enum and then the body is just a list of possible values separated by commas. There's nothing particularly special about this from a TypeScript perspective. You can access the enum values like you were accessing a class's static members: ShapeType.Rectangle. As I said earlier though, the real magic behind enums in TypeScript is how they are generated in JavaScript, so let's take a look at the output of our enum:

var ShapeType;
(function (ShapeType) {
    ShapeType[ShapeType["Rectangle"] = 0] = "Rectangle";
    ShapeType[ShapeType["Circle"] = 1] = "Circle";
    ShapeType[ShapeType["Line"] = 2] = "Line";
    ShapeType[ShapeType["Freehand"] = 3] = "Freehand";
})(ShapeType || (ShapeType = {}));

There is quite a bit of JavaScript here to represent something as simple as number mapping. However, if you look at it more deeply you will see that TypeScript is creating a two-way mapping between the named constant and the number it is mapped to. This creates a number of interesting ways in which you can access the values of an enum. Take a look at the following code snippet and consider what the output might be:

alert(ShapeType[ShapeType.Rectangle]);

ShapeType has been created inside of an anonymous function that returns an object that has been given two properties for each member of the enum. Taking advantage of JavaScript's dynamic typing system, TypeScript adds a property with the string value of the member name and maps it to an integer value. That integer value is then simultaneously added as a property of the ShapeType object and is mapped to the string value of the named member. So if you thought that the value returned previously was the string representation of the named member, then you were correct!

Enums

Now that we are familiar with how an enum works, let's look some more at the individual members of an enum. We know that enums represent two-way mapping between a number and a string, but where does that number come from? In the ShapeType example, we just saw each member was just given a name, the number was generated by the compiler. This works well and creates a sequential set of numbers for us to access, but a little more control over these values would be nice. TypeScript has therefore provided two types of enum members that can be created: constant members, and computed members. What we looked at earlier were all constant members with auto-generated constant values. These numbers are sequential starting from zero unless a constant value is provided to a member. Then, all of the subsequent members of the enum will be in sequence with the number given.

Computed members are still named constants but the integer value they are mapped to is provided by an expression. This can be either an inline expression or a function call to another segment of code. The only stipulation on the expression that you provide is that it returns a number. As you can see in the following code segment, we have modified our previous enum, ShapeType, to generate some specific indexes as well as create a computed member:

function GetEnumValue(): number {
    return Date.now();
}
enum ShapeType {
    Rectangle = 3,
    Circle,
    Line,
    Freehand,
    Random = GetEnumValue()
}

As you can see, we have created a function that returns an integer representing the current time using the global Date object available in JavaScript. We also set the first constant member to an integer value of our choosing. When the compiler parses this, all of the members in the enum will grow sequentially from this value. Let's take a look at the resulting JavaScript now and see how a computed member will look at runtime:

function GetEnumValue() {
    return Date.now();
}
var ShapeType;
(function (ShapeType) {
    ShapeType[ShapeType["Rectangle"] = 3] = "Rectangle";
    ShapeType[ShapeType["Circle"] = 4] = "Circle";
    ShapeType[ShapeType["Line"] = 5] = "Line";
    ShapeType[ShapeType["Freehand"] = 6] = "Freehand";
    ShapeType[ShapeType["Random"] = GetEnumValue()] = "Random";
})(ShapeType || (ShapeType = {}));

As you can see, the expression provided to the computed member is built directly into the enum declaration generated. This expression will be evaluated at runtime but only when ShapeType is initialized. Once the expression has been run, the result will remain a member of the ShapeType object. Therefore, in the preceding example ShapeType.Random is equivalent to ShapeType.Random as long as the ShapeType enum stays in memory. You may be wondering right now what the usefulness is of being able to change the constant members' numeric sequence.

The one piece of information we haven't covered on enums so far is that their definitions can be merged. If two enum declarations are placed in different segments of code with the same type name they will contribute to the same object. You can see this in the last line of the enum declaration in the resulting JavaScript. If the object exists then each new property is added to the existing object; otherwise, a new object is created and the properties are applied.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset