Writing in the front

Recently I wrote a requirement that currently there are two list data, one is a list of questions, one is a list of answers. The two list data have a common data structure: avatar, name, and time. Therefore, we extract the following TS types according to the data interface fields in the data background.

/** QsData {avator? : string time? : number | string name? : string quesitons: {title: string picture: string[]}} / / AsData {avator? : string time? : number | string name? : string answers: { text: string audio? : { url: string total: number } } }Copy the code

Type decoupling decouples

Clearly, good code follows the DNR (Do not Repeat) principle that the same repeated declaration fragment is not good. The above repeated interface declarations can be broken down by function and module

Export interface DataAvator {avator? : string time? : number | string name? Export interface Qs {quesitons: {title: string picture: String []}} export interface As {answers: {text: string audio? : { url: string total: number } } }Copy the code

Interface with

But the declaration that we need is the complex data type that we started with, now we need to assemble the simple data type, how do we assemble it elegantly that’s the question? That’s when I thought of utility types, where we can quickly get complex types from simple types. I wrote a previous article about getting into tool generics and I talked about ts in this area. Ok, we can now construct a mixed TS utility class.

type Mixin<T, X> = {
  [P in keyof (T & X)]: (T & X)[P]
};
Copy the code

It can also be simpler

type Mixin<T, X> = T & X;
Copy the code

We use mixins to assemble complex list data as follows:

DataAvator<T> = Mixin<DataAvator, T>; DataAvator<T> = DataAvator<T>; Export interface AskConfig {asker: MixWithDataAvator<Qs> answer? : MixWithDataAvator<As>} export Type AskConfigList = AskConfig[];Copy the code

So far so good, it’s pretty loose compared to the two data declarations we defined at the beginning. No matter which part of the declaration you maintain, you don’t need to change much.

Ts: & and |

Have to say, the preface was really long, now only & derivation and | symbols. Going back to the Mixin section above, this solution is all about ampersand. When we connect the type with & is ts of cross type, connect with | is joint type. I wasn’t clear on either of these concepts at first, so I took a closer look at what was useful in the project.

These two type concepts can be understood by thinking of intersection and union. (PS: Very important! Setting aside the concepts of intersection and union in mathematical sets, most articles on the Internet are misleading because they are completely different from the following sets of classes. Take a look at the picture below:First look at the type intersection on the left:

There is type 1: blue object type 2: small object, when the intersection of the two types, the resulting type is blue and small object. Therefore, the understanding of an intersection type is that a new type is created by the intersection of types and that this type contains all the attributes of the types involved in the intersection.

Look again at the type union on the right:

Existence type 1: blue object type 2: red objects, when two type and set, the understanding of joint type is the type and set after the creation of a trash can, all types of participation and set like a trash can in the trash, when we use the combined type, like a trash can pick up garbage, or pick up objects is blue, or red objects.

Summary: & Cross type: produces a new type that contains all attributes. | joint types: produce a set of contains all types of choice type.

The joint type

interface A {
  name: string
  age: number
}

interface B {
  name: number
  id: string
}

type Union = A | B;
const c: Union
Copy the code

When we use union type assignments, data structures can only be of form A or B

When we read attributes using the union type, we can only get their common attribute name PS (IDEA syntax hint). If you are accessing non-common attributes, you must do type protection to prevent bugs.

Cross type

When we read properties using cross types, we can get all property names of all types, and assign values that satisfy all types of structure



It is important to note that when we cross a type that has the same property name but different property types, the property will be of type never



The reason for this is simple: by crossing operations, name cannot be both number and string, so it becomes never.

Never type

Never: the type of the value that does not exist. In the above example, there is no value of the attribute name that is either a number or a string. It’s easier to understand. The never type is also used in some cases, but assigning to never when writing multiple code streams such as if else/switch throws syntactical exceptions in time to help avoid case omissions. For a more detailed look at how the never type helps code check, you can read this article

conclusion

I searched a lot of articles on the Internet and read a lot of complicated explanations. I sorted out what I understood in a simpler way. The first day of rework in 2021 is also the first article ~. I hope it will be helpful to those who are also confused about these two concepts.