I am participating in the Mid-Autumn Festival Creative Submission Contest. Please see: Mid-Autumn Festival Creative Submission Contest for details.

The preface

Recently began to learn TS, found a lot of difficulties, after this hurdle, found TS operators like pinyin is the basis of Chinese characters, learn TS operator, is the top priority to learn TS, we will have a detailed understanding of TS operators today.

typeof

In TypeScript, the typeof operator can be used to get the declaration of a variable, or the typeof an object. Let’s look at two small examples

// example 1 interface People {name: string; age: number; } const variableDai: People = { name: 'coolFish', age: 24 }; type formDai= typeof variableDai; Function toArray(x: number): Array<number> {return [x]; function toArray(x: number): Array<number> {return [x]; } type Func = typeof toArray; // -> (x: number) => number[]Copy the code

Summary: Note that in example 1 we defined a constant variableDai and then got its type, assigning it to type formDai.

Keyof

The keyof operator can be used with all the keys in an object and returns the key-worthy type.

interface Person {
    name: string;
    age: number;
}
​
type allKey = keyof Person; // "name" | "age"
Copy the code

Of course we can use this feature to do special operations, such as iterating over an empty array and returning the combined types of all the properties that an array has

interface Person {
    name: string;
    age: number;
}
​
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"
Copy the code

Example 3

type K3 = keyof { [x: string]: Person }; // string | number
Copy the code

Because the key here is index type, so is the string | number

in

In is used to iterate over enumerated types

type Keys = "a" | "b" | "c"
​
type Obj =  {
  [p in Keys]: any
} 
//{ a: any, b: any, c: any }
Copy the code

infer

In conditional type statements, a type variable can be declared and used with infer.

Type Head<T extends Array<any>> = T extends [Head: infer H,...rest: any[]]? H : never; // Test case Type H0 = Head<[]> // Never type H1 = Head<[1]> // 1 type H2 = Head<[3, 2]> // 3Copy the code

In the example above, we use infer to define a type variable as the first term and then narrow the type to obtain the first term.

extends

When we define generics that don’t want to be too flexible, or when we want to inherit some classes, we can add generic constraints through the extends keyword

interface mustLength { length: number; } function mustTakeLength<T extends mustLength>(arg: T): T { console.log(arg.length); return arg; } mustTakeLength(3)// Error, number doesn't have a .length property loggingIdentity({length: 10, value: 3}); / / 10Copy the code

We define a mustLength interface, and the input parameter is bound by that interface and must have a length attribute. Otherwise, an error will be reported

Let’s look at one more example to understand extends

type User = { id: number; kind: string; }; Function makeCustomer<T extends User>(u: T): T {// Error (TS compiler version: v4.4.2) // Type '{id: number; kind: string; }' is not assignable to type 'T'. // '{ id: number; kind: string; }' is assignable to the constraint of type 'T', // but 'T' could be instantiated with a different subtype of constraint 'User'. return { id: u.id, kind: 'customer' } }Copy the code

Why does the above code report an error? Because T is bound by User, it must have the type of User, but it can have more than one type, return only two types, if there are more types, there will be a problem, so the solution is as follows

type User = { id: number; kind: string; }; // T assignable User function makeCustomer<T extends User>(u: T): T { return { ... u, id: u.id, kind: 'customer' } }Copy the code

Use the extension operator to return extra arguments.

Partial

Partial

is used to make all attributes of a type optional. This method combines keyof and in.

type Partial<T> = { [P in keyof T]? : T[P]; }; interface User { name:string, age:number, department:string } type optional = Partial<User> /**type optional = { name? : string | undefined; age? : number | undefined; department? : string | undefined; } * * /Copy the code

Required

Required

is used to make all attributes of a type mandatory, similar to Partial

type Required<T> = { [P in keyof T]-? : T[P]; };Copy the code

Different from Partial, Partial is plus, right? And this is minus, right? .

Readonly

Readonly

makes all properties of a type read-only, which means they cannot be reassigned.

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
Copy the code

Prefix each key with readOnly

Record

Record

converts the values of all properties in K to type T

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
Copy the code

Summary: Iterate through the typed properties in K, and assign each Key to an instance of type T

type petsGroup = 'dog' | 'cat' | 'fish';
interface IPetInfo {
    name:string,
    age:number,
}
​
type IPets = Record<petsGroup, IPetInfo>;
​
const animalsInfo:IPets = {
    dog:{
        name:'dogName',
        age:2
    },
    cat:{
        name:'catName',
        age:3
    },
    fish:{
        name:'fishName',
        age:5
    }
}
​
Copy the code

Pick

The effect of Pick

is to sort out the subproperties of a type into subproperties that contain some of the properties of that type
,k>

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
Copy the code

T is multitype, K is partial type of T, and then you go through K to get the key, and then you go into T to get the corresponding value.

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
​
type TodoPreview = Pick<Todo, "title" | "completed">;
​
const todo: TodoPreview = {
  title: "Clean room",
  completed: false
};
Copy the code

Exclude

Exclude

removes a type that belongs to another type
,u>

type Exclude<T, U> = T extends U ? never : T;
Copy the code

Never is returned if T can be assigned to U, T is returned otherwise. The net effect is to remove certain types of U from T. Here, the feature of never is mainly used. Never is the lowest type, and the combination of any type equals that type has achieved the effect of removal.

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
Copy the code

Omit

Omit

is used to Omit all attributes of type T except type K
,>

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
​
type TodoPreview = Omit<Todo, "description">;
​
const todo: TodoPreview = {
  title: "Clean room",
  completed: false
};
Copy the code

To achieve the above result, we can use Pick and Exclude. Pick can select what we want, Exclude can Exclude what we don’t want, so we just need to Exclude description first, and then select the rest from Todo. Here is the code for the implementation.

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Copy the code