Angular is a hassle, and you have to learn RxJS and TS. To be fair, RxJS does take time to understand, but TS shouldn’t be too difficult to use, especially from a tool user’s perspective.

A couple of concepts in TS

  • TS is a superset of JS. Or JS is also TS. How do you understand that? For example, if you change the suffix of any JS file to TS and run it as TS, it is the same as running JS directly.
    // The following code is also true in TS. const a = 1; function add(a, b) { return a + b; }Copy the code
  • TS = JS + Type, that is, TS is JS with the Type constraint.
    const a :number = 1;
    
    function add(a: number, b: number) {
      return a + b;
    }
    Copy the code
  • The TS type is not run-time, but compile-time, primarily for the editor. Attempts to determine the type of a variable at runtime are not guaranteed (except for the method of determining the type supported in JS)

The use of types in TS

  • Basic types in JS:
    let a: number
    let b: string
    Copy the code
  • Function parameters and return values
    function func(a: string): string {}
    
    (a: string): string => {
    }
    Copy the code
  • Of course, since Function is also Object in JS, this province is also a type of Object
    Let func: (a: string) => stringCopy the code
  • In addition to primitive types, class, like any other language, is of course a type:
    class Test {
    }
    
    const test: Test = new Test();
    Copy the code
  • We know that JS can be used directly{}To create the object, not necessarily with the help ofclass. forobjectWe can just give it to youobjectDefine the type.
    const test: { a: number; b: number; } = { a: 1, b: 2 }; // You can also give it a name by using the 'interface' keyword interface Test {a: string; b: string; } // or the 'type' keyword type Test {a: number; b: number; }Copy the code
  • Arrays are similar:
    const data: string[]
    Copy the code
  • A type can not only be a base type, class, function, interface, it can even be a concrete value
    const a: 1 = 1; / / of course, also can be more than one value const a: 1 | 2 | 3 = 1; / / naturally | both sides can be of various types of const a: 1 | string | (arg: any []) = > voidCopy the code

Type inference in TS

Unlike some strongly typed languages, where variable types must be explicitly specified, TS can dynamically recommend types under certain conditions.

  • The type of the variable is inferred from the assignment:

    let a = 1
    a = '' // Type 'string' is not assignable to type 'number'
    Copy the code
  • Function inferred the return type from the code

    function add(a: number, b: number) {
      return a + b;
    }
    
    let c: string = add(1, 2); // Type 'number' is not assignable to type 'string'
    Copy the code

In addition to the above inference for omitted types, type inference is performed in TS code logic in order to reduce the scope of variables, mainly for the type in the if block.

The logic is also simple, if in the if condition, if the type can be specified, in the current block, the inferred type will be used. Because if is concrete business logic, it must also be code that satisfies JS syntax. So in JS, the methods to determine the type are nothing more than the following:

  • Typeof is used to determine the type number/string/function/object in JS
    function addOne(a: number | string) {
     if (typeof a === 'string') {
       return a + '_1'; // (parameter) a: string
     }
    
     return a + 1; // (parameter) a: number
    }
    Copy the code
  • The empty check. Of course, we can also handle whether the block is empty or not by using if.
    function addOne(a? : number | string) { if (a) { console.log(a); // (parameter) a: string | number } }Copy the code
  • Judging instanceof class
    Similar to Typeof, no further details are required.Copy the code
  • In Determines the interface. In fact, at runtime, the code doesn’t know anything about interfaces, so how do we distinguish between different interfaces? The answer is the difference field.
    interface A {
      a: string;
    }
    
    interface B {
      a: string;
      b: string;
    }
    
    function testFunc(param: A | B) {
      if ('b' in param) {
        console.log(param); // (parameter) param: B
      }
    }
    Copy the code
  • Of course, the field difference is not only the difference of “have” and “have not”, but also the difference of type, provided that the field used for the difference must be union type:
    interface A {
       type: 'a';
       a: number;
     }
    
     interface B {
       type: 'b';
       a: number;
     }
    
     function testFunc(param: A | B) {
       if (param.type === 'a') {
         console.log(param); // (parameter) param: B
       }
     }
    Copy the code

Type manipulation (creating another type based on one type)

Type programming. If we say that TS is to add type to JS, it is not comprehensive enough. The power of TS lies in that type itself is programmable. That is, we can create a new type based on a certain type of input. Of course, you can think of it as programming for a paradigm. For the simplest example, we need to write a method that changes the property value of an object:

Function updateProperty<T>(obj: T, key: string, value: any):void {}Copy the code

The question here is, obviously, now that we know what type obj is currently, can we put explicit type constraints on key and value?

function updateProperty<
  T extends object, 
  K extends keyof T, 
  V extends T[K]>(obj: T, key: K, value: V) {}

const obj: B = { type: 'b', a: '111' };
updateProperty(obj, 'a', 1111); // Argument of type 'number' is not assignable to parameter of type 'string'.
Copy the code

Programming for types in TS, the core of course is Create Types.

  • Generics (the foundation of type programming)
  • keyof
  • typeof
  • indexed access types
  • conditional types
  • mapped types
  • template literal types

It is easy to see that the core of type programming is the type programming of object

  • Get all key types of object:keyof
    interface A {
      type: 'a';
      a: number;
    }
    
    type KeyOfA = keyof A;
    const key: keyof A = 'a';
    Copy the code
  • Obtain the value type of the object key:T['a'] (indexed access types)
    interface A {
      type: 'a';
      a: number;
    }
    
    let a: A['a'] = '11'; // Type 'string' is not assignable to type 'number'
    Copy the code
  • Create an object type according to the key and value types and their corresponding relationships:mapped types
    [key: string] {string} / /, of course, the key can also be a group of string/number/symbol (union type) {[key in 'a' | 'type'] : Type Test = {[key in keyof A]: A[key]}Copy the code

The object related

  • Dynamically get variable types:typeof
    const currentValue: string = '';
    type CurrentType = typeof currentValue; // type CurrentType = string
    Copy the code
  • Type conditional judgment:conditional types
  • Template type:template literal types