typescript中的enum和类型转换
Enums
An enum is a way to organize a collection of related values. Many other programming languages (C/C#/Java) have
an enum data type but JavaScript does not. However TypeScript does. Here is an example definition of a TypeScript enum:
enum CardSuit {
Clubs,
Diamonds,
Hearts,
Spades
}
// Sample usage
var card = CardSuit.Clubs;
// Safety
card = "not a member of card suit"; // Error : string is not assignable to type `CardSuit`
Enums and Numbers
小鸡打架
TypeScript enums are number bad. This means that numbers can be assigned to an instance of the enum, and so can anything el that is compatible with number.
enum Color {
Red,
社会变革的先导Green,
Blue
}
var col = Color.Red;
col = 0; // Effectively same as Color.Red
Enums and Strings
Before we look further into enums let's look at the JavaScript that it generates, here is a sample TypeScript:
enum Tristate {
Fal,
True,
Unknown
}
神之左手魔之右手generates the following JavaScript:
var Tristate;
(function (Tristate) {
疯狂购物
Tristate[Tristate["Fal"] = 0] = "Fal";
Tristate[Tristate["True"] = 1] = "True";
Tristate[Tristate["Unknown"] = 2] = "Unknown";
})(Tristate || (Tristate = {}));
let's focus on the line Tristate[Tristate["Fal"] = 0] = "Fal";. Within it Tristate["Fal"] = 0should be lf explanatory, i.e.
ts "Fal" member of Tristate variable to be 0. Note that in JavaScript the assignment operator returns the assigned value (in this ca 0). Therefore the next thing executed by the JavaScript runtime is Tristate[0] = "Fal". This means that you can u the Tristate variable to convert a string version of the enum to a number or a number version of the enum to a string. This is demonstrated below:
enum Tristate {
Fal,
True,
Unknown
}
console.log(Tristate[0]); // "Fal"
console.log(Tristate["Fal"]); // 0
console.log(Tristate[Tristate.Fal]); // "Fal" becau `Tristate.Fal == 0`
Changing the number associated with an Enum
By default enums are 0 bad and then each subquent value increments by 1 automatically. As an example consider the following:
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
However you can change the number associated with any enum member by assigning to it specifically. This is demonstrated below where we start at 3 and start incrementing from there:
enum Color {
DarkRed = 3, // 3
DarkGreen, // 4
DarkBlue // 5
}
TIP: I quite commonly initialize the first enum with = 1 as it allows me to do a safe truthy check on an enum value.
Enums are open ended
Here is the generated JavaScript for an enum shown again:
var Tristate;
(function (Tristate) {
Tristate[Tristate["Fal"] = 0] = "Fal";
Tristate[Tristate["True"] = 1] = "True";
Tristate[Tristate["Unknown"] = 2] = "Unknown";
})(Tristate || (Tristate = {}));
We already explained the Tristate[Tristate["Fal"] = 0] = "Fal"; portion. Now notice the surrounding code (function (Tristate) {
/*code here */ })(Tristate || (Tristate = {})); specifically the (Tristate || (Tristate = {})); portion. This basically captures a local
variable TriState that will either point to an already defined Tristate value or initialize it with a new empty {} object.
This means that you can split (and extend) an enum definition across multiple files. For example below we have split the definition for Color into two blocks
enum Color {
Red,
Green,
Blue
}
enum Color {
DarkRed = 3,
DarkGreen,
DarkBlue
}
Note that you should reinitialize the first member (here DarkRed = 3) in a continuation of an enum to get the generated code not clobber values from a previous definition (i.e. the 0, 1, ... so on values). TypeScript will warn you if you don't anyways (error message In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element.).
Enums as flags
One excellent u of enums is the ability to u enums as Flags. Flags allow you to check if a certain condition from a t of conditions is true. Consider the following example where we have a t of properties about animals:
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
EatsFish = 1 << 2,
Endangered = 1 << 3
}
Here we are using the left shift operator to move 1 around a certain level of bits to come up with bitwi disjoint
numbers 0001, 0010, 0100 and 1000 (the are decimals 1,2,4,8 if you are curious). The bitwi operators | (or) / & (and)
/ ~ (not) are your best friends when working with flags and are demonstrated below:
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
}
function printAnimalAbilities(animal) {
var animalFlags = animal.flags;敌人的反义词是什么
if (animalFlags & AnimalFlags.HasClaws) {
console.log('animal has claws');
}
if (animalFlags & AnimalFlags.CanFly) {
console.log('animal can fly');
耳聋的治疗方法}
if (animalFlags == AnimalFlags.None) {
胡萝卜丝鸡蛋饼
console.log('nothing');
}
}
var animal = { flags: AnimalFlags.None };
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws;
printAnimalAbilities(animal); // animal has claws
animal.flags &= ~AnimalFlags.HasClaws;
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly;
printAnimalAbilities(animal); // animal has claws, animal can fly
Here:
we ud |= to add flags
a combination of &= and ~ to clear a flag
| to combine flags
Note: you can combine flags to create convenient shortcuts within the enum definition
路遥马亡e.g. EndangeredFlyingClawedFishEating below:
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
EatsFish = 1 << 2,
Endangered = 1 << 3,
EndangeredFlyingClawedFishEating = HasClaws | CanFly | EatsFish | Endangered,
}
Const Enums
If you have an enum definition like the following:
enum Tristate {
Fal,
True,
Unknown
}
var lie = Tristate.Fal;
The line var lie = Tristate.Fal is compiled to the JavaScript var lie = Tristate.Fal (yes, output is same as input). This means that at execution the runtime will need to lookup Tristate and then Tristate.Fal. To get a performance boost here you can mark the enum as a const enum. This is demonstrated below:
const enum Tristate {
Fal,
True,
Unknown
}
var lie = Tristate.Fal;
generates the JavaScript:
var lie = 0;
< the compiler:
1. Inlines any usages of the enum (0 instead of Tristate.Fal).
2. Does not generate any JavaScript for the enum definition (there is no Tristate variable at runtime) as its usages are
inlined.
Const enum prerveConstEnums
Inlining has obvious performance benefits. The fact that there is no Tristate variable at runtime is simply the compiler helping you out by not generating JavaScript that is not actually ud at runtime. However you might want the compiler to still generate the JavaScript version of the enum definition for stuff like number to string or string to number lookups as we saw. In this ca you can u the compiler flag --prerveConstEnums and it will still generate the var Tristate definition so that you can u Tristate["Fal"] or Tristate[0] manually at runtime if you want. This does not impact inlining in any way.
Enum with static functions
You can u the declaration enum + namespace merging to add static methods to an enum. The following demonstrates an example where we add a static member isBusinessDay to an enum Weekday: