In front-end development, it is actually very easy to get started with TS, as long as you master some basic type knowledge, you can gradually transition JS to TS application. However, when our project is very large and complex, it is easy to define some types as any in the development process. Here we mainly introduce the advanced types of TS. To help you better define variable types, always reduce the use of any.

Introduction to generics

Generics are an important concept in strong typing. Using generics can help us improve the reuse of our code. Generics are represented by <>\color{DarkTurquoise}{<>}<> Angle brackets. The characters in Angle brackets are called type variables \color{DarkTurquoise}{type variables} type variables and are used to indicate types.

Generics allow programmers to write code in strongly typed programming languages using types that are specified later and specified as parameters when instantiated

Example:

 public testGenerics<T>(arg: T): T {   // T is just a placeholder, but everyone uses it by convention
    return arg;
  }
  
  const str = this.testGenerics<string>('just test generics');
Copy the code

The type T in this code is undefined until the testGenerics function is called. Only after the method is called can we know exactly what type T stands for. If we pass it the type, it will return the type

Introduction to Advanced Types

In real development, you might use some basic types like String, number, Boolean, etc., but once you understand some advanced types, you can define more complex and flexible interface types.

1. The joint type (|)

The rules and logic for joining types are the same as “or” \color{DarkTurquoise}{” or “} “or”, indicating that the type is joining any one of multiple types

T | U

// demo
interface IPerson {
  age: number;
  gender: 'woman' | 'male';
}

const person: Iperson = {
  age: 25;
  gender: 'woman'
}
Copy the code

2. Cross type (&)

Cross types can combine multiple types into a single type with the same writing and logic as “with” \color{DarkTurquoise}{” with “} “with”

 T & U
 
 // Demo now has two classes, and we can implement a new property type definition by crossing types
 interface IPerson {
   age: number;
   gender: string;
 }

 interface IJob {
   title: string;
   years: number;
 }

 const life: IPerson & IJob = {
    age: 30.gender: 'nv'.title: 'development'.years: 10};Copy the code

3. Type Alias (Type)

Type alias, it allows you to create a name for the type, the name is the alias type, which you can use this alias, many places of and when necessary, you can change the alias value (type), a replacement, in order to achieve the effect of several application, type the alias is similar to the syntax is declaring variables, only need to put the const, Let is the type keyword.

type Alias = T | U
 
 // demo
 type sex =  'woman' | 'male';
 
 interface IPerson {
  age: number;
  gender: sex;
}
Copy the code

The difference between type aliases and interfaces

  • A type alias can express the type expressed by an interface, but it is also more fine-grained and more arbitrary than an interface
  • Interfaces can be implemented by a class (implements) or can be normalized using extends, but type aliases are not
  • Type aliases can be used in conjunction with keyOf naturally

4. Type index (keyOf)

Keyof is similar to Object.keys and is used to obtain the associative type of the Key in an interface

// demo
interface IPerson {
  age: number;
  gender: sex;
}

// With keyOf, whenever the IPerson is changed, the type type is automatically changed as well

type personKeys = keyof IPerson;
/ / equivalent to the
type personKeys = 'age' | 'gender';
Copy the code

5. Type constraints (extends)

Extends is primarily used to constrain generics. Unlike class, extends is used for inheritance purposes.

 // demo
 type BaseType = string | number | boolean;
 
 public testGenerics<T extends BaseType>(arg: T): T {
   return arg;
 }
 
 this.testGenerics('123'); / / success
 this.testGenerics({}); / / fail
Copy the code

Extends is often used with keyof. For example, if we have a method that gets the value of an object, but the object is uncertain, we can use extends and keyof to constrain it.

// Constrain the value of key based on the obj passed in
function getValue<T.K extends keyof T> (obj: T, key: K) {
  return obj[key]
}
Copy the code

6. Condition types (U? X, Y)

The syntax of conditional types is the same as that of ternary expressions, and is generally used in cases where the type is uncertain

  T extends U ? X : Y // If T is a child of U, then it is of type X, otherwise Y
  
  type Extract<T, U> = T extends U ? T : never; // If T is a child of U, return T, otherwise discard
Copy the code

Let’s take a look at the Extract\color{DarkTurquoise}{Extract}Extract, which is used to Extract public properties.

 interface ITeacher {
  age: number;
  gender: sex;

}

interface IStudent {
  age: number;
  gender: sex;
  homeWork: string;
}

type CommonKeys = Extract<keyof ITeacher, keyof IStudent>; // "age" | "gender"
Copy the code

7. Type mapping (in)

In is used for type mapping, traversing keys of existing interfaces or traversing associative types

type Test<T> = {
   [P in keyof T]: T[P];  
};
/ / keyof T equivalent type ObjKeys = 'a' | 'b'
/ / P in ObjKeys equivalent to perform the logic of a forEach, traverse the 'a' | 'b'

interface IObj {
  a: string;
  b: string;
}

type newObj = Test<IObj>;
Copy the code

8. The non-empty assertion operator (!)

The non-empty assertion operator removes undefined and NULL from a variable, simply by adding one after the variable! Can, ignore the variable of undefined | null:

Introduction to tool generics

There are also many tool generics built into TS. Here are some common tool generics

1. Partial

Color {DarkTurquoise}{DarkTurquoise}{optional} All attributes of an interface are set to the optional state. This is done by first retrieving all attributes of the type variable T through keyof T, then loop through in, and finally add? To each attribute.

 type Partial<T> = {
    [P inkeyof T]? : T[P] }// demo
 interface ITeacher {
  age: number;
  gender: sex;
}

const teacherA: Partial<ITeacher> = {age: 28};  // Partial is used. Gender is not assigned
Copy the code

2. Required

\color{DarkTurquoise}{Required}{Required} Required. The main difference is that Partial? Replace it with -?

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

3. Exclude

Exclude does the exact opposite of Extract. If the type in T does not exist in U, it is returned, otherwise it is discarded.

 type Exclude<T, U> = T extends U ? never : T
 
 //demo
 
 interface ITeacher {
  age: number;
  gender: sex;

}

interface IStudent {
  age: number;
  gender: sex;
  homeWork: string;
}

type ExcludeKeys = Exclude<keyof ITeacher, keyof IStudent>; // "homeWork"
Copy the code

4. Pick

Pick is mainly used to extract some attributes in the interface \color{DarkTurquoise}{extract some attributes in the interface} extract some attributes in the interface, we can use this generic to extract the attributes of the interface, thus generating a new attribute

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

// demo
interface IStudent {
  name: string
  age: number
  homework: string
}

type StudentA = Pick<IStudent, "name" | "age"> // Extract the name and age attributes from this interface

const zs: StudentA = {
  name: 'zs'.age: 18
}
Copy the code

5. Omit

Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit Omit

type Omit<T, K extends keyof any> = Pick<
  T, Exclude<keyof T, K>
>

// demo
interface IStudent {
  name: string
  age: number
  homework: string
}

type StudentA = Omit<IStudent, "name"> // Remove the name attribute from this interface

const zs: StudentA = {
  age: 18.homework: 'Recite the text'
}
Copy the code

conclusion

TypeScript 4.0 has added many new features to TypeScript. This article will help you learn more about TypeScript and reduce or even get rid of AnyScript