hi! Everybody is good! I am a medical examiner, a treatment department front-end code ape 🐒, dialogue with the code, listen to the voice of their heart, looking forward to everyone’s praise 👍 and attention ➕.
Extension type — enumeration
In the last article, WE talked a lot about TS base types, so why do we have extended type enumerations? We all know that nothing comes out of nowhere, but to solve a specific problem. Enumerations are just one of the extension types, such as type aliases, interfaces, and classes
So what does enumeration mean?
📢 enumeration is the process of putting a truckload of watermelons on the stand one by one.
What does it do?
📢 enumeration is usually used to constrain the value range of a variable, not only the variable, of course, but also the parameter of the function or the return value of the function. For example, the range of sex sex of the constraint variable is not male or female, and it can not be male or female 😂
Those of you who read my last article may recall that the variable gender was also defined in that article, and was treated with literals and union types
For example 🌰 :
// It is also possible to constrain variables by combining literals with union types
let gender : "Male" | "Female";
Copy the code
Literals with union types also serve the purpose of constraining variables, so how is it different from enumerations? Do not think, is certainly encountered can not solve the problem, otherwise the whole enumeration out pointless. I’m going to talk about it in detail, and you can learn:
- What are the opportunities for enumerations
- What problem does it solve
First, the problem of literal types
1. Duplicate code is generated in the type constraint position, which can be usedType the alias
Solve the problem
For example 🌰 :
We define a gender variable in our code. The type constraint is male or female. Gender can only be assigned to male or female, but no other value is available.
// Define a gender variable and constrain it to male or female
let gender : "Male" | "Female";
// Gender can be assigned to male or female
gender = "Female";
gender = "Male";
// Query the function by gender
function searchUsers(g:"Male" | "Female") {}Copy the code
Gender constraints can be seen in the code variables and function parameters of produce the same code “male” | “female”, seen in front of a friend may have to succumb to, as mentioned earlier a type alias, can solve this problem, it is as follows:
// Define a type alias
type Gender = "Male" | "Female";
// Define a gender variable and constrain it to male or female
let gender : Gender;
// Gender can be assigned to male or female
gender = "Female";
gender = "Male";
// Query the function by gender
function searchUsers(g:Gender) {}Copy the code
As a result, duplicate code is generated at type constraint locations, which can be solved using type aliases. But other problems cannot be solved by type aliasing
2. The logical meaning is confused with the real value, resulting in a large number of changes when the real value is modified
For example 🌰 :
// Define a type alias
type Gender = "Male" | "Female";
// Define a gender variable and constrain it to male or female
let gender : Gender;
// Gender can be assigned to male or female
gender = "Female";
gender = "Male";
// Query the function by gender
function searchUsers(g:Gender) {}Copy the code
In the code above, the type alias Gender is defined and the constraint is male or female. In the subsequent code writing process, Gender will definitely be assigned male or female. We can imagine that the Gender variable is heavily used in the assignment of tens of thousands of lines of code. It is too vulgar to use male and female constraints, and it is not classy. Change the beauty and the handsome boy, as follows:
// Define a type alias
type Gender = "Handsome boy" | "The beauty";
// Define a gender variable and constrain it to male or female
let gender : Gender;
// Gender can be assigned to male or female
gender = "Female";
gender = "Male";
// Query the function by gender
function searchUsers(g:Gender) {}Copy the code
The gender variable is used literally in hundreds of thousands of lines of code. Once the constraint name is changed, everything that follows must be changed, resulting in a lot of changes. Why? Root cause is a logical meaning and real values confusion together, the constraints of beauty and handsome boy is the real value, but whether it’s a handsome boy, beauty, or male, the female is a meaning, said biological gender male and female, when using literal type can lead to real values and logical meaning of value is the corresponding, However, when assigning values to variables, only the real value can be assigned. The logical meaning value is unchanged, but the real value is changed, resulting in a lot of modification. This problem can not be solved by using type aliases
3. Literal types do not enter compilation results
Literal types are not compiled and will disappear after running, as follows:
If we want to dynamically read what values are in the variable in TS and display them on the page, we cannot do this because TS has lost the variable constraint information at compile time.
The second and third problems need to be solved by enumeration
Ii. “Tao” of enumeration
1. How do I define an enumeration?
// Enumeration fields indicate what values are available for genderEnum Enumeration name {Enumeration field1Value:1, enumeration fields2Value:2, enumeration fields3Value:3,}// Take gender as an example
enum Gender {
male = "The beauty",
female = "Handsome boy",}Copy the code
Control, from the above enumerated definition, just found that there are two values, an enumeration field name, the other is value, there will be two values, is the logical meaning and the true value of confusion, and logical meaning and real value in the enumeration separated, on the left is the logical meaning of value, on the right is the real value, there are no longer needed after enumeration type alias, Modify the code for the problem literal type:
// Define a type alias
/ / type Gender = "handsome boy" | "beauty";
// Use enumeration instead
enum Gender {
male = "The beauty",
female = "Handsome boy",}// Define a gender variable and constrain it to male or female
let gender : Gender;
// Gender can be assigned to male or female
//gender = "female ";
// Gender = "male ";
// After enumeration is used, the real value cannot be assigned
gender = Gender.male;
gender = Gender.female;
// Query the function by gender
function searchUsers(g:Gender) {}Copy the code
This solves the second problem with literal types: confusion between the logical meaning and the real value, which can cause a lot of subsequent code changes. After using enumerations, you can change the actual values directly in the future, with only one change, because all the subsequent code will use the logical meaning of the values, which will not change.
An additional benefit of enumerations is that they participate in compiling code and appear in the result of compilation. Enumerations are represented as objects in JS, as follows:
In the compiled JS file, we first declare a variable Gender, and then pass Gender to the function. If Gender has no value, it is assigned to an object, and then add a property male to the object, which is assigned to beauty. And female is assigned to be handsome, so it can be found that enumeration will participate in the compilation of the code, so we can dynamically print the attribute values in the enumeration during the compilation and running of the code. As follows:
However, the previous type aliases cannot do this because type aliases disappear at compile time, whereas enumerations do not.
So if we need to use a range of values at run time, we should use enumerations and prevent future code changes, we should separate the logical meaning from the real value, and we should use enumerations
📢 the question is: when should we use type aliases? When do you use enumerations?
👉 answer:
In fact, there is no need to tangle, as long as the value range can use enumeration, it is correct 😁
2. Enumeration rules
-
Enumeration values can be strings or numbers
Strings have just said that enumerations of genders are strings, and we call them numeric enumerations
-
Numeric enumerations are automatically incremented; only numbers have this feature
For example 🌰 :
Define a data enumeration that is the values of the fields from Monday to Sunday. When Monday is assigned to 1, the other values are incremented from the previous value. If the first value is not assigned, it starts at 0.
-
The result of compiling numeric enumerations is different from that of compiling string enumerations
This is the result of compiling the numeric enumeration
3. Best practices for enumeration
- Try not to have both string and number fields in an enumeration
- When using enumerations, try to use the names of the enumerated fields instead of the real values, to separate the logical values from the real values
- Use enumerations when you can, use type aliases, and you can’t escape those two problems
Enumeration extended knowledge – bit enumeration
An enumeration can also be called enumeration operation, the enumeration is for digital enumeration, string enumerated are not enough, here for chestnut 🌰 to illustrate bit operations, we all know there are a lot of operating a file permissions, can read, write, create, delete, permissions have corresponding values, here is the number, cannot exceed the range, as follows:
enum Permission{
Read,
Write,
Create,
Delete
}
Copy the code
These are the four permissions for a file, but there is a problem, sometimes we need to combine these permissions, some can only read and write can not create and delete, maybe we will write like this:
enum Permission{
Read,
Write,
Create,
Delete,
ReadAndWrite,
WriteAndCreate,
/ /... And so on, too many to write
}
Copy the code
These four combinations have A44 permutations and combinations, which is 24 results. If you add or delete points in the future, you will write more, so it is very inconvenient to write all of them in Permission. A very clever way to do this is to assign the fields 1, 2, 4, 8, as follows:
enum Permission{
Read = 1,
Write = 2,
Create = 4,
Delete = 8
}
Copy the code
In other words, 1 = 2 to the 0,2 = 2 to the 1, 4 = 2 to the 2, 8 = 2 to the 4, they’re all 2 to the n, and if you go to binary, one of them is 1, and the rest are 0, and the binary of 1 is 0001, The binary number of 2 is 0010, the binary number of 4 is 0100, and the binary number of 8 is 1000. We can indicate whether we have the permission by whether there is a 1 in the binary number. For example, 0001 is 1 in the fourth digit, which indicates that we have the read permission. 0011 can represent read and write permissions, so we can use these basic permissions to combine new permissions
1. How to combine new permissions
For example, if we want to combine read and write permissions, we can do this:
enum Permission{
Read = 1./ / 0001
Write = 2./ / 0010
Create = 4./ / 0100
Delete = 8 / / 1000
}
//1. How to combine types
// Use or calculate
let rwP = Permission.Read | Permission.Write;
Copy the code
We need to pay attention to is the | here is not a joint type of TS, call or operation, here it is an operation in one of them
Bit operations: refers to the two Numbers after converted into a binary operation, using every bit operations, there are many | : or operation is one of them
First, we get the read binary and the write binary: 0001,0010, and they do the or, and the rule of the or is to compare each digit, and if one digit is 1, then the result is 1, otherwise it is 0, so the final result is 0011
0001
/ / or operation
0010
// The final result is 0011
Copy the code
2. How do I check whether I have a permission
After an or operation, rwP yields a number that is passed into the function as a target value for comparison with permissions
enum Permission{
Read = 1./ / 0001
Write = 2./ / 0010
Create = 4./ / 0100
Delete = 8 / / 1000
}
//1. How to combine types
// Use bit operations
let rwP = Permission.Read | Permission.Write;
/** * Check that the target does not contain the "p" permission *@param Target Target value *@param P A permission */
function hasPermission(target:Permission,p:Permission) {
return (target & p) === p
}
// check whether rwP has "read" permission
let result = hasPermission(rwP,Permission.Read);
// check whether rwP has Read permission
console.log(result);/ / return true
Copy the code
To determine whether a permission is granted, it is simple to determine whether the last bit of binary 0001 is equal to 1.
Let’s look at this code again (target & p) === p, where & is called and, which is also a bit operation
And operation: compare the binary of two numbers, as long as the binary of both numbers is 1 in the same position, and vice versa. For example, if 0011 and 0010 are calculated and the value is 0010, they are equal to the permission. Otherwise, they do not have the permission.
3. How do I delete a permission
enum Permission{
Read = 1./ / 0001
Write = 2./ / 0010
Create = 4./ / 0100
Delete = 8 / / 1000
}
//1. How to combine types
// Use bit operations
let rwP = Permission.Read | Permission.Write;
/** * Check that the target does not contain the "p" permission *@param Target Target value *@param P A permission */
function hasPermission(target:Permission,p:Permission) {
return (target & p) === p
}
// check whether rwP has "read" permission
let result = hasPermission(rwP,Permission.Read);
// 3. How do I delete a permission
rwP = rwP ^ Permission.Write;
console.log(hasPermission(rwP,Permission.Write));// Return false to clear writable permissions
Copy the code
To delete a Permission, run the rwP = rwP ^ Permission.Write command. You can just reassign, and in this code ^ means xor
Xor: Compares the binary of two digits. The result is 0 for the same digits, and 1 for the different digits. For example, if the previous permission was 0011, delete the read permission of 0010
If we encounter optional permissions in the future, we can use bitwise operations to deal with it, which is very elegant and scalable
The last
Thank you very much for reading the last 😘. If you think this article is helpful to you, you may wish to pay attention to ➕+ like 👍+ collect 📌+ comment ➕. Your support is the biggest motivation for me to update.