An in-depth understanding of TypeScript translated into Chinese is of high quality

Writing in the front

Most of the content in this document, the above Chinese translation documents are available, but its translation cavity is too tired to see. When I was sharing with several students, I made this document which is not only a note, but also a “lesson plan”. At the same time referred to some blogs and their own understanding of the content of the test, adjusted the learning order. Some concepts in the translation document are not clearly defined or concretely defined. Finally, some content was added and modified according to the feelings and discussions during the sharing. Send up for you to do a reference, but also welcome you to correct.

Common Basic Commands

cnpm i -g typescript    // Install ts globally
tsc hello.ts            // Compile the hello.ts file
tsc --init 		// Generate a tsconfig.json file in which you can configure some compilation options. It can then run directly
			// TSC, you do not need to specify the file name, the compiler will compile according to the configuration in tsconfig.json

tsc -w			// After a file change is detected, it will recompile (hot update).

cnpm i -g ts-node 	// Install the TS-Node module.
ts-node hello.ts 	// Can execute ts code directly
Copy the code
  • The statement space

    The declaration space of TS is divided into type declaration space and variable declaration space.

    The variable declaration space contains content that can be used as variables, and the type declaration space contains content that can be used as type annotations.

    class Foo {}		/ / class
    interface Bar {}	/ / interface
    type Bas = {};		// Type alias
    Copy the code

    All three are type declarations, where class is both a type and a variable, but interface and type are only types and cannot be used as variables.

    let foo: Foo;		// The basic usage of type annotations
    let bar: Bar;		
    let bas: Bas;
    Copy the code

    Just as type declarations cannot be used as variables, variable declarations cannot be used as annotations.

    const foo = 123;
    let bar: foo; 		// ERROR: "cannot find name 'foo'"
    Copy the code
  • The type system

    1. The base type
      • boolean

      • string

      • number

        let num: number;
        let str: string;
        let bool: boolean;
        
        num = 123;
        num = 123.456;
        num = '123'; // Error
        
        str = '123';
        str = 123; // Error
        
        bool = true;
        bool = false;
        bool = 'false'; // Error
        Copy the code
      • array

        Different from js, strongly typed Array element type declaration, Array all types are the same

        let boolArray: boolean[];	// Type array, elements can only be Booleans
        
        boolArray = [true.false];
        console.log(boolArray[0]); // true
        console.log(boolArray.length); / / 2
        
        boolArray[1] = true;
        boolArray = [false.false];
        
        boolArray[0] = 'false'; // Error
        boolArray = 'false'; // Error
        boolArray = [true.'false']; // Error
        
        const womens:[string.string.number[[] [] ='kenan'.'tingting'.22],
                ['kenan'.'tingting'.22],
                ['kenan'.'tingting'.22]]Copy the code
      • enum

        An organization’s way of collecting associated variables, enumeration types serve to provide semantics for certain numbers

        enum CardSuit {
          Clubs,
          Diamonds,
        }
        // Simply use enumerated types
        let Card = CardSuit.Clubs;
        // Type safe
        Card = 'not a member of card suit'; // Error: String cannot be assigned to 'CardSuit' // type
        enum Color {
            Red, 
            Green, 
            Blue
        }    // the default values from the first variable are 0,1,2. If the first value is a number, not explicitly followed, it automatically +1
        let c: Color = Color.Green;  / / value is 1
        // Enumeration is actually approximately equal to {key: 0, key1:1, '0' : key, '1' : key1}, and the default is numeric enumeration
        // Enumerate compiled code similar to the following
        //var Tristate;
        //(function(Tristate) {
        // Tristate[(Tristate['False'] = 0)] = 'False';
        // Tristate[(Tristate['True'] = 1)] = 'True';
        // Tristate[(Tristate['Unknown'] = 2)] = 'Unknown';
        //})(Tristate || (Tristate = {}));
        enum Color {
            Red = 'red',
            Green = 'green',
            Blue = 'blue'}    // Explicit assignment, non-numeric explicit assignment must be assigned to each
        let c: Color = Color.Green;  / / value for red
        
        Copy the code
      • tuple

        A tuple can be thought of as an extension of an array, representing an array with a known number and type of elements. Specifically, we know the type of the element at each position in the array.

        let nameNumber: [string.number];
        
        // Ok
        nameNumber = ['Jenny'.221345];
        
        // Error
        nameNumber = ['Jenny'.'221345'];
        
        // Tuples can be assigned to arrays, but arrays cannot be assigned to tuples. There is no difference when compiling to JS
        Copy the code
      • any

        Use any type sparingly and avoid using ts as anyScript

      • void

        Void 0 is the same as undefined, but because undefined is not a keyword and is a constant, some libraries use void 0 instead of undefined for comparison.

      • null

      • undefined

      • never

        A function that never returns (or always throws an error) returns a value of type never

      • Symbol

        To use ‘Symbol’ in TS, configure [“es6”] in lib of ‘tsconfig.json’.

      • object

        Object represents a non-primitive type, i.e. a type other than number/ string/ Boolean/symbol/ null/ undefined. In fact, the object type is rarely used, because its annotation is very non-specific, and generally uses interfaces to mark more specific object types

    2. Structured type
      • Class (es6)
        // Review the es6 class
        // Attributes and methods
        class Animal{
            name;// Define attributes: This is new to ES6 and previously could only be defined in constructor via this.name
            constructor(name){
                this.name = name;
            }
            static onLoad(){
                alert('000');
            }// Static method
            showName(){
                console.log(this.name); }}let animal = new Animal('dog');
        animal.showName();
        
        // Class inheritance: Extends implements inheritance, calling the constructor or properties of the parent class and ordinary methods via super() or super.xx
        class Dog extends Animal{// If the parent class is inherited, the constructor must call the superclass constructor super(...).
            constructor(name){
                super(name);// Call the parent constructor to assign the name attribute to the parent
            }
            // override the parent showName() method
            showName(){
                super.showName();// Call the method of the parent class to print the value of the parent class name property}}let dog = new Dog(Tom Dog);
        dog.showName();
        
        // Access property setter,getter: intercepts the value and storage of the name property
        class Animal2{
            //name; Note 1: If a memory accessor is written and has the same name, it must be defined here
            constructor(name){
            	//this.name = name;
                //this._name=name
            }
            set name(name) {// This method only starts when the name attribute is set to a value, instead of setName(),
                // this. Name = name; Doing so will keep calling this listener function, causing stack overflow
                //this.name = name; //RangeError: Maximum call stack size //exceeded
                console.log('setter: ' + _name);
                //this.name = name;
                this._name=name
            }
            get name() {console.log('getter... ');
                //return this.name;
                return this._name;
            }
        // Static method :static
        class Animal3{
            // constructor(name){
            // static this.name = name; // Static variables cannot be defined this way
            // }
            static isAnimal(animal){
                console.log(animal instanceofAnimal3); }}IsAnimal =function(animal){console.log(animal instanceof //Animal3); }
        Copy the code
      • Class (ts)

        Public (default modifiers for properties and methods) : public

        Private: private

        Protected: Modifiers are also private variables, but are accessible in subclasses

        //TypeScript class usage
        //public(default modifiers for properties and methods) private and protected
        //private
        class Animal5 {
            private name;
            public constructor(name) {
                this.name = name; }}let animal5 = new Animal5('Jack');
        // console.log(animal5.name); // error:
        // animal5.name = 'Tom'; //error: private variables cannot be accessed
        // Subclasses also cannot access the parent's private class
        Copy the code

        The abstract abstract class

        abstract class Animal7{
            abstract name;				// Abstract attributes are rarely used
            constructor(name){			// Abstract classes cannot create new objects
                //this.name = name; //
            }
            public abstract showName();	// Abstract methods
        }
        
        Copy the code
      • interface interface

        Interface is a specification, a look at this specification, you know what he is used for, and extensible, can be maintained.

        interface Name {
          first: string;
          second: string; three? :string; / / not required
        }
        
        let name: Name;
        name = {
          first: 'John'.second: 'Doe'
        };
        
        name = {
          // Error: 'Second is missing'
          first: 'John'
        };
        
        name = {
          // Error: 'Second is the wrong type'
          first: 'John'.second: 1337
        };
        Copy the code
        Interface development

        The interface can be declared again anywhere to extend it

        // Lib a.d.ts
        interface Point {
          x: number.y: number
        }
        declare const myPoint: Point
        
        // Lib b.d.ts
        interface Point {
          z: number
        }
        
        // Your code
        myPoint.z // Allowed!
        Copy the code
        Interface inheritance
        interface Shape {     // Define interface Shape
            color: string;
        }
        
        interface Square extends Shape {  // Inherits interface Shape
            sideLength: number;
        }
        
        // One interface can inherit multiple interfaces to merge multiple interface members. Separate the interfaces to be inherited with commas.
        interface PenStroke {
            penWidth: number;
        }
        
        interface Square extends Shape, PenStroke {
            sideLength: number;
        }
        Copy the code
        Class implementation interface
        interface Point {
          x: number;
          y: number;
        }
        
        class MyPoint implements Point {
          x: number;	
          y: number; // Same as Point
        }
        
        interface Point {
          x: number;
          y: number;
          z: number; // New member
        }
        
        class MyPoint implements Point {
          // ERROR: missing member 'z
          / / implements
          x: number;
          y: number;
        }
        
        interface Crazy {
          new() : {hello: number;
          };
          //aaa (): {
          // hello: number;
          / /};
        }
        class CrazyClass implements Crazy {
          constructor() {
            return { hello: 123 };
          }
          //aaa () {
          // return { hello: 123 };
          / /}
        }
        // If this method is tested, it will return an error. Replace new with another method, such as aaa
        // Because
        const crazy = new CrazyClass(); // crazy would be { hello:123 }
        Copy the code
    3. Inline type annotations

      Similar to inline styles in HTML tags, they are defined directly on elements without class definitions. Annotations are defined directly after variables, without declaring interfaces, classes, or aliases.

      let name: {
        first: string;
        second: string;
      };
      
      name = {
        first: 'John'.second: 'Doe'
      };
      
      name = {
        // Error: 'Second is missing'
        first: 'John'
      };
      
      name = {
        // Error: 'Second is the wrong type'
        first: 'John'.second: 1337
      };
      Copy the code
    4. The generic

      Many algorithms and data structures do not depend on the actual type of the object, but want to provide constraints in each variable. A degree of type safety can be achieved while not identifying the type.

      Generics in Java: Defer typing until you create an object or call a method to specify a particular type. Ts is perfectly ok with this definition.

      function reverse<T> (items: T[]) :T[] {
          //T stands for Type. It is usually used as the first Type variable name when defining generics
          // This is what common generic variables mean:
          //K (Key) : indicates the Key type in the object.
      	V (Value) : indicates the Value type of the object.
      	//E (Element) : indicates the Element type.
        const toreturn = [];
        for (let i = items.length - 1; i >= 0; i--) {
          toreturn.push(items[i]);
        }
        return toreturn;
      }
      
      const sample = [1.2.3];
      let reversed = reverse(sample);
      
      console.log(reversed); / / 3, 2, 1
      
      // Safety
      reversed[0] = '1'; // Error
      reversed = ['1'.'2']; // Error
      
      reversed[0] = 1; // ok
      reversed = [1.2]; // ok
      
      
      function identity <T.U> (value: T, message: U) : T {
        console.log(message);
        return value;
      }
      console.log(identity<Number.string> (68."Semlinker"));
      // Generic interface
      interface Identities<V, M> {
        value: V,
        message: M
      }
      Copy the code
      A generic interface
      interface Identities<V, M> {
        value: V,
        message: M
      }
      function identity<T.U> (value: T, message: U) :Identities<T.U> {
        console.log(value + ":" + typeof (value));
        console.log(message + ":" + typeof (message));
        let identities: Identities<T, U> = {
          value,
          message
        };
        return identities;
      }
      
      console.log(identity(68."Semlinker"));
      Copy the code
      A generic class
      interface GenericInterface<U> {
        value: U
        getIdentity: () = > U
      }
      
      class IdentityClass<T> implements GenericInterface<T> {
          //implements implements, meaning that IdentityClass must satisfy GenericInterface
          //GenericInterface may cause IdentityClass errors to synchronize code
      
        value: T
      
        constructor(value: T) {
          this.value = value
        }
      
        getIdentity(): T {
          return this.value
        }
      	
      }
      
      const myNumberClass = new IdentityClass<Number> (68);
      console.log(myNumberClass.getIdentity()); / / 68
      
      const myStringClass = new IdentityClass<string> ("Semlinker!");
      console.log(myStringClass.getIdentity()); // Semlinker!
      Copy the code
      Generic constraint

      Example: Make sure the property exists as follows

      function identity<T> (arg: T) :T {
        console.log(arg.length); // Error
        return arg;
      }
      
      interface Length {
        length: number;
      }
      function identity<T extends Length> (arg: T) :T {
        console.log(arg.length); // Get the length attribute
        return arg;
      }
      Copy the code
      Checks whether a key exists on an object
      interface Person {
        name: string;
        age: number;
        location: string;
      }
      The //keyof operator, introduced in TypeScript 2.1, can be used to get all keys of a type whose return type is a union type
      type K1 = keyof Person; // "name" | "age" | "location"
      type K2 = keyof Person[];  // number | "length" | "push" | "concat" | ...
      
      function getProperty<T.K extends keyof T> (obj: T, key: K) :T[K] {
        return obj[key];
      }
      Copy the code
    5. The joint type

      Joint type also incorporating multiple types of a type, said “or” relationship, with | connect to multiple type:

      function setWidth(el: HTMLElement, width: string | number) {
          el.style.width = 'number'= = =typeof width ? `${width}px` : width;
      }
      Copy the code
    6. Cross type

      A relation for “and”, using & to join multiple types, often used for object merging:

      interface A {a:number};
      interface B {b:string};
      
      const a:A = {a:1};
      const b:B = {b:'1'};
      constab:A&B = {... a,... b};Copy the code
    7. Type the alias
      type StrOrNum = string | number;
      
      / / use
      let sample: StrOrNum;
      sample = 123;
      sample = '123';
      
      // Check the type
      sample = true; // Error
      
      type Text = string | { text: string };
      type Coordinates = [number.number];
      type Callback = (data: string) = > void;
      Copy the code

      You are advised to use interfaces, which can be implemented or extends. Type aliases are more commonly used to semantically semantics some cross and union types.

  • function

    1. Parameter annotation
      function foo(sampleParameter: { bar: number }) {}
      Copy the code
    2. Return type annotation
      interface Foo {
        foo: string;
      }
      
      // Return type annotated as `: Foo`
      function foo(sample: Foo) :Foo {
        return sample;
      }
      
      
      // If you do not annotate the return type of a function, the compiler will infer the type
      function foo(sample: Foo) {
        return sample; // inferred return type 'Foo'
      }
      Copy the code
    3. Optional parameters
      function foo(bar: number, bas? :string) :void {
        // ..
      }
      
      foo(123);
      foo(123.'hello');
      // If the caller does not provide this argument, you can provide a default value (use = someValue after the argument declaration)
      function foo(bar: number, bas: string = 'hello') {
        console.log(bar, bas);
      }
      
      foo(123); // 123, hello
      foo(123.'world'); // 123, world
      Copy the code
    4. overloading
      / / overloaded
      function padding(all: number);
      function padding(topAndBottom: number, leftAndRight: number);
      function padding(top: number, right: number, bottom: number, left: number);
      // Actual implementation that is a true representation of all the cases the function body needs to handle
      function padding(a: number, b? :number, c? :number, d? :number) {
        if (b === undefined && c === undefined && d === undefined) {
          b = c = d = a;
        } else if (c === undefined && d === undefined) {
          c = a;
          d = b;
        }
        return {
          top: a,
          right: b,
          bottom: c,
          left: d
        };
      }
      
      padding(1); // Okay: all
      padding(1.1); // Okay: topAndBottom, leftAndRight
      padding(1.1.1.1); // Okay: top, right, bottom, left
      
      padding(1.1.1); // Error: Not a part of the available overloads
      // Function overloading in TypeScript has no runtime overhead. It only allows you to record how you want the function to be called,
      Copy the code

      Ts function overload comparison is useless, but more than a parameter verification function. In other words, during the function call, the parameters will be checked. Only when the type, sequence, and number of parameters passed are the same as those of the overloaded function defined, the call can be successful. Otherwise, an error will be reported. Return value types are not validated (function overloading is independent of return value types)

  • Environmental statement

    Declaration files complement type annotations to JS code. This will not prompt the JS file “missing type” in the TS compilation environment.

    Even if you only write js code, you can install the declaration file, because if you use vscode, it will automatically analyze the js code, and if a corresponding declaration file exists, vscode will use the contents of the declaration file as a code hint.

    Declare variables use the keyword DECLARE to indicate the type of the global variable that follows the declaration.

    declare var foo: any;
    foo = 123; // allow
    Copy the code

    The file name of the declaration file must end in.d.ts. Any path/file name of the declaration file in the project is recognized by the TS compiler, but in practice it is recommended to put the declaration file in the root directory.

    @types

    Popular plugins usually have a declaration file, such as jquery’s declaration file:

    npm install @types/jquery --save-dev
    
    import * as $ from 'jquery';
    
    // now you can use any $in this module :)
    Copy the code

    Json can be configured to introduce meaningful types to the compileroptions. types option:

    {
      "compilerOptions": {
        "types" : [
          "jquery"]}}Copy the code
  • The module

    Global module

    The default is the global module, in the global namespace. The following

    / / foo ts file
    const foo = 123;
    
    / / bar. Ts file
    const bar = foo; // allowed
    Copy the code
    File module

    File modules are also called external modules. If you have import or export at the root of your TypeScript file, it creates a local scope in the file.

    / / foo ts file
    export const foo = 123;
    
    / / bar. Ts file
    const bar = foo; // ERROR: "cannot find name 'foo'"
    
    // To use it in bar.ts files, you must import it explicitly
    import { foo } from './foo';//import also makes the bar.ts file a module
    const bar = foo; // allow
    Copy the code
  • Type index (KEYOF)

    Ts keyof is similar to js object. keys, which can be used to obtain the key value of an Object type:

    type A = keyof {a:1.b:'123'} // 'a'|'b'
    type B = keyof [1.2] // '0'|'1'|'push'... , more methods and properties on the Array prototype
    let c:A = 'c' // Error, value can only be a or b
    Copy the code
  • Mapping types (Readonly, Pick, Record, etc…)

    Before looking at Readonly, look at Readonly:

    The TypeScript type system allows you to use ReadOnly to tag properties in an interface

    function foo(config: { readonly bar: number.readonly bas: number }) {
      // ..
    }
    
    const config = { bar: 123.bas: 123 };
    foo(config);
    
    // Now you can make sure that 'config' cannot be changed
    
    type Foo = {
      readonly bar: number;
      readonly bas: number;
    };
    
    / / initialization
    const foo: Foo = { bar: 123.bas: 456 };
    
    // Cannot be changed
    foo.bar = 456; // Error: foo.bar is a read-only property
    
    class Foo {
      readonly bar = 1; // OK
      readonly baz: string;
      constructor() {
        this.baz = 'hello'; // OK}}/ / interface
    Copy the code

    Mapping types are more like utility functions that modify types, such as Readonly, which makes each property read-only:

    type A  = {a:number.b:string}
    type A1 = Readonly<A> // {readonly a: number; readonly b: string; }
    //ts source code Readonly
    type Readonly<T> = {
        readonly [P in keyof T]: T[P];
    };
    Copy the code
    Partial, which makes all properties optional
    type A  = {a:number.b:string}
    type A1 = Partial<A> // { a? : number; b? : string; }
    Copy the code
    Required, making the attributes mandatory
    typeA = {a? :number, b? :string}
    type A1 = Required<A> // { a: number; b: string; }
    Copy the code
    Pick<T,K>, only the selected attributes are reserved. K represents the attribute key value to be reserved
    type A  = Pick<{a:number.b:string.c:boolean}, 'a'|'b'>//{a:number,b:string}
    Copy the code
    Omit<T,K> implement exclusion of selected attributes
    type A  = {a:number.b:string}
    type A1 = Omit<A, 'a'> // {b:string}
    Copy the code
    Record<K,T>, creates a type,K represents the type of the key value,T represents the type of the value
    type A1 = Record<string.string> / / equivalent {[x: string] : string}
    Copy the code
  • Extends (Condition type)

    T extends U ? X : Y
    Copy the code

    The type used to represent the type is indeterminate. If the type of U can represent T, then return X, otherwise Y

    type A =  string extends '123' ? string :'123' / / '123'
    type B =  '123' extends string ? string :123 // string
    Copy the code