The theme to share with you today is to do genre gymnastics together.
It is mainly divided into 4 sections to be introduced:
In the background chapter, what is type, what is type safety, how to implement type safety, what is type gymnastics?
to understand the meaning of type gymnastics.
Before we understand what a type is, let’s introduce two concepts:
A variable of type boolean allocates 4 bytes of memory, while a variable of type number allocates 8 bytes of memory.
The number type can do addition, subtraction, multiplication, division and other operations, boolean can not, the composite type of different types of objects available in different methods, such as Date and RegExp, the different types of variables mean that the operation of the variable can be done differently.
In summary, it can be concluded that types are abstract definitions of different content provided by programming languages.
Now that you understand the concept of types, what is type safety?
A simple definition is that type safety is about doing only the operations that are allowed for that type. For example, for the boolean type, addition, subtraction, multiplication, and division operations are not allowed, and only true and false are allowed.
When we can achieve type safety, we can greatly reduce the potential problems in the code and improve the quality of the code a lot.
So, how do you do type safety?
Two types checking mechanisms are introduced here, dynamic type checking and static type checking.
Some of the definitions of types introduced above are some familiar background introductions about types, and this chapter returns to the theme concept of this sharing, type gymnastics.
Before we learn about type gymnastics, let’s introduce the 3 types of systems.
A simple type system, which checks only on the declared type, such as an addition function, can add integers or decimals, but in a simple type system, you need to declare 2 functions to do this.
The generic type system, which supports type parameters, can dynamically define types by passing parameters to make types more flexible.
However, in some scenarios that require logical operations on type parameters, such as a function type that returns the value of a property of an object.
Type programming system, which not only supports type parameters, but also can do various logical operations on type parameters, such as the function type mentioned above that returns a property value of an object, and can obtain a function type by keyof, T[K] to logically operate.
To summarize the above, type gymnastics is type programming, doing various logical operations on type parameters to produce new types.
The reason why it is called gymnastics is because of its complexity, the right side is a function type that parses the arguments, which uses a lot of complex logical operations, and then analyzes the implementation of this type after the type programming method is introduced first.
After becoming familiar with the concept of type gymnastics, we will continue to understand what types of type gymnastics, what operating logic is supported, and what are the operation routines.
The main types of type gymnastics are listed in the figure. TypeScript reuses the underlying and composite types of JS, and adds tuples, interfaces, enums, and other types, which should be commonly used in the daily development process of type declarations, without going into detail.
The focus is on the arithmetic logic supported by type programming.
TypeScript supports nine kinds of operation logic, such as condition, deduction, union, crossover, and mapping of union types.
The condition judgment is the same as the js logic, both return a if the condition is met, otherwise return b.
Restrict types by extending constraint syntax.
The derivation is a regular match similar to js, and when the formula conditions are met, the variables in the formula can be extracted, directly returned or processed again.
A joint representative can be one of several types.
Crossover represents a merge of types.
keyof is used to get all keys of a certain type, and its return value is a union type.
T[K] is used to access the index to obtain the union type of the value corresponding to the index.
in is used to traverse the union type.
as is the key used to modify the mapping type.
Based on the 9 types of operational logic described above, I have summarized 4 types of routines.
The first type of routine is pattern matching for extraction.
Pattern matching extraction means extending a pattern type by type, putting the parts that need to be extracted into local variables declared by infer.
For example, use pattern matching to extract function parameter types.
First use extends to restrict the type parameter must be of type Function.
The formula is then matched with extends for the parameter type, and when the formula is satisfied, the variable Args in the formula is extracted.
Implements the extraction of function parameter types.
The second type routine is to reconstruct and make a transformation.
Reconstructing to do transformation means that if you want to change, you need to reconstruct the new type, and you can do some filtering and transformation of the original type in the process of constructing the new type.
For example, implement a reconfiguration of a string type.
First restrict the parameter type to be a string type.
The formula is then matched with extends for the parameter type, extracting the variables in the formula, First Rest, and encapsulating them in an Uppercase.
Implemented the first letter uppercase string literal type.
The third type of routine is recursive reuse as a loop.
TypeScript itself does not support loops, but loops can be achieved by recursively completing an indeterminate number of type programming.
For example, the inversion of array types is implemented recursively.
First the restriction parameter must be an array type.
The formula is then matched with extends and if the condition is met, it calls itself, otherwise it returns directly.
An array inversion type is implemented.
The fourth type routine is the array length to count.
Type programming itself does not support addition, subtraction, multiplication, and division, but you can complete the addition, subtraction, multiplication, and division of numeric values by recursively constructing an array of specified lengths and then taking the length of the array.
For example, the addition of type programming is implemented through array length.
Start by recursively creating an array type that can generate any length
Then create an addition type that implements the addition operation by the length of the array.
The third part of the sharing is the practice of type gymnastics.
The concept of type gymnastics and the commonly used operating logic were shared earlier.
Let’s use these arithmetic logic to parse the advanced types built into TypeScript.
Traverse the index with the in operator, adding a ? The prefix implementation makes the index an optional new mapping type.
Traverse the index with the in operator, removing the ? The prefix implementation makes the index a new mapping type that is mandatory.
Traversing indexes with the in operator, adding a readonly prefix to all indexes implements a new mapping type that makes indexes read-only.
First restrict that the second parameter must be the key value of the object, and then traverse the second parameter through the in operator to generate a new map type implementation.
Traverses the union type K with the in operator to create a new mapping type.
Remove part of the union type by using the extends operator to determine whether parameter 1 can be assigned to parameter 2 and, if so, return never.
In contrast to the Exclude logic, a portion of the union type is retained by determining whether parameter 1 can be assigned to parameter 2 and, if not, returning never.
Remove the filtered index by combining the advanced types Pick and Exclude.
Gets the value type of an unknown level of Promise by recursion.
There are also many advanced types, and the implementation ideas are mostly the same as the type routines introduced above, which will not be repeated here.
The focus is on the complexity of type gymnastics in the background section, with examples of function types that parse string arguments.
As shown in the demo figure, this function is used to parse the specified string format into an object format.
For example, get the value of a in the string a=1&b=2.
The commonly used type declaration methods are shown in the following figure:
The parameter type is string, the return type is Record
The following is to override the function type that parses string parameters through type gymnastics.
First restrict the parameter type to be a string type, then match the formula a&b for the parameter, resolve a to the map type of key value if the formula is satisfied, recursively resoften b to the ParseQueryString type, and continue parsing until the a&b formula is no longer satisfied.
Finally, you get a precise function return type, res.a = 1.
In summary, the type of gymnastics is introduced from 3 aspects.
The first point is the background of type gymnastics, understanding what is type, what is type safety, and how to achieve type safety;
The second point is to be familiar with the main types of type gymnastics, the supported logical operations, and summarize the 4 types of routines;
The third point is type gymnastics practice, which parses the implementation of advanced types built into TypeScript and writes some complex function types by hand.
From this, we learned that the scene that needs to dynamically generate types must be done with type programming, even if some scenarios can be programmed without types, but the use of type programming can have more accurate type hints and checks, reducing potential problems in the code.
Here are the references and sample source code of this sharing, welcome to read more:
Reference to TypeScript Gymnastics Clearance Cheats: https://juejin.cn/book/7047524421182947366
Sample source code: https://github.com/jiaozitang/ts-demo