TypeScript associative types

Joint type refers to a variable has a variety of possible types, a variety of types with symbol between | segmentation can be a base type:

  let content: string | number = "content"; // Content can be either a string or a number
  content = 123;
Copy the code

It can also be an object type:

  interface Student {
    sid: string
    name: string
  }
  
  interface Teacher {
    tid: string
    subject: string
  }
  
  let man: Student | Teacher = {  // Man can be a Student or a Tacher
    sid: '1001'.name: 'XiaoCai'
  }
  man = {
    tid: '2001'.subject: 'sports'
  }
Copy the code

TypeScript type protection

As type assertion

When a variable has more than one possible type, the AS keyword is used to determine the type

  interface StrProp {
    isStr: boolean
    name: 'String'
  }

  interface NumProp {
    isStr: boolean
    age: 18
  }

  function say(arg: StrProp | NumProp) {
    // console.log(arg.name) // An error was reported
    if(arg.isStr) {
      // When the isStr attribute of arg is true, we conclude that arG is of type StrProp
      console.log((arg as StrProp).name)
    } else {
      console.log((arg as NumProp).age)
    }
  }
Copy the code

In grammar,

We can also determine the type of a variable by determining whether it has a property by using in

  interface StrProp {
    isStr: boolean
    name: 'String'
  }

  interface NumProp {
    isStr: boolean
    age: 18
  }

  function say(arg: StrProp | NumProp) {
    if('name' in arg) {
      console.log(arg.name)
    } else { // TypeScript automatically determines the else part here
      console.log(arg.age)
    }
  }
Copy the code

Typeof grammar

  function test(arg: string | number) {
    if(typeof arg === 'string') {
      return arg.split(' ')}else {
      return 2 * arg
    }
  }
Copy the code

Enum Enum type

Enumerated types are commonly used to define constants

  // enum Sex {// Enumeration type can not initialize the value, the default value is 0
  // MALE,
  // FEMALE,
  // UNKNOW
  // }

  enum Sex {
    MALE = 1.// Can be given a starting value, automatic increment
    FEMALE,
    UNKNOW
  }

  function checkSex(sex: Sex) {
    let result = ' ';
    switch(sex) {
      case Sex.MALE:
        result = 'male';
        break;
      case Sex.FEMALE:
        result = 'woman';
        break;
      case Sex.UNKNOW:
        result = 'unknown';
        break;
      default:
        break;
    }
    return result;
  }

  console.log(checkSex(1)) / / 'male'
Copy the code

Generic TypeScript

The concept of generics

If you want to implement a function whose return value type is the same as the parameter type, you can write:

  function fun(arg: string) :string {
    return arg
  }
Copy the code

Or this:

  function fun(arg: number) :number {
    return arg
  }
Copy the code

But these are too limited to be true for all cases, so you can use generics. Generics are generic types, defined by <>, usually with a single capital letter like

  function fun<T> (arg: T) :T { 
    return arg // The return value type is the same as the parameter type
  }
Copy the code

Generic array

Two ways to write generic arrays

  / / T []
  function fun<T> (arg: T[]) :T[] {
    return arg.reverse()
  }
  fun<string>(['a'.'b'.'c'.'d'])
  // fun(['a', 'b', 'c', 'd']) generics also support type inference

  // Array<T>
  function func<T> (arg: Array<T>) :Array<T> {
    return arg.reverse()
  }
  func<number>([1.2.3.4.5])
Copy the code

Multiple generic definitions

Generics can define more than one, similar in usage to one

  function fun<T.P> (first: T, second: P) :T.P] {
    return [first, second]
  }
  fun<string, number>('string'.123)
Copy the code

Inheritance in generics

Generics can be constrained by inheritance

  interface Key {
    key: number
  }

  function fun<T extends Key> (arg: T) :T { // The generic T inherits the interface Key, so the parameter must contain the Key attribute
    return {
      ...arg,
      key: new Date().getTime() + arg.key
    }
  }

  fun({
    key: 123.name: 'test'
  })
Copy the code

Simple use of generics

Implement an AXIos method that accepts both url and payload parameters. The type of the received parameter and the return value are different depending on the URL

  interface Todo {
    // Todo interface
    id: number;
    name: string;
    done: boolean;
  }

  let todos: Todo[] = [
    // Initial data
    {
      id: 1.name: Sb "1".done: false}, {id: 2.name: "Agent 2".done: true,},]; enum Urls {Todo[] todo [] todo []
    TODOS = "/api/todos".// Todo state todo interface. The parameter type is number. The return value type is Boolean
    TOGGLE = "/api/toggle".// Add the todo interface. The parameter type is todo and the return value type is Boolean
    ADD = "/api/add",}// Define a tool type
  // Return a custom key based on the generic input value
  type Key<U> = U extends Urls.TODOS ? "todos" : 
                U extends Urls.TOGGLE ? "toggle" : 
                U extends Urls.ADD ? "add" : "other";

  // Obtain the corresponding Key based on the tool type Key, and obtain the corresponding parameter type based on the Key
  type Payload<P> = {
    todos: any;
    toggle: number;
    add: Todo;
    other: any;
  }[Key<P>];

  // Obtain the corresponding Key based on the tool type Key and the corresponding result type based on the Key
  type Result<R> = {
    todos: Todo[];
    toggle: boolean;
    add: boolean;
    other: any;
  }[Key<R>];

  function axios<T extends Urls> (url: T, payload? : Payload
       ) :Promise<Result<T>> | never {
    let res;
    switch (url) {
      case Urls.TODOS: // Get toDO data, no arguments, return type todo []
        res = todos.slice();
        break;
      case Urls.TOGGLE: // Change the toDO state with type number and return Boolean
        const todo = todos.find(({ id }) = > id === payload);
        if(todo) { todo.done = ! todo.done; } res =true;
        break;
      case Urls.ADD: // Add todo with toDO type and return Boolean type
        // add! To allow undefined and NULL to compiletodos.push(payload!) ; res =true;
        break;
      default:
        throw new Error("Unknow api!");
    }
    return Promise.resolve(res as any);
  }

  axios(Urls.ADD, {
    id: 3.name: 'Take notes'.done: false
  }) // Add a piece of data
  console.log(axios(Urls.TODOS)) // Get all data
  axios(Urls.TOGGLE, 2) // Switch the done state of data 2
Copy the code