Revealing A ngular 2 (1): Introduction to TypeScript

Keywords: TypeScript angular Attribute Programming

3.1 Overview of TypeScript

3.1.1 overview

3.1.2 installation

  • Check whether npm is installed
  • Next, we use the 2.0 official version of TypeScript. The installation commands are as follows:

    npm install -g typescript@2.0.0
    
  • Write the first Typescript program and save it to hello.ts. The code in the file is as follows:

    console.log('hello TypeScript!');
    
  • Compile the TypeScript file through tsc:

    tsc hello.ts    
    

3.2 Basic Types

  • Boolean type
  • Number
  • String type
  • Array type (array)
  • Meta-ancestor type
  • Enumeration type (enum)
  • Any value type
  • null and undefined
  • void type
  • never type

3.2.1 Boolean Type

let flag:boolean=true;
flag=1;//Error reporting. Number type values cannot be assigned to Boolean type variables

3.2.2 Digital Types

let binaryLiteral:number=0b1010;//Binary system
let octalLiteral:number=0b1010;//Octal number system
let decLiteral:number=6;//Decimal system
let hexLiteral:number=0xfood;//Hexadecimal

3.2.3 String Type

let name:string="Angular";
let years:number=5;
let words:string = hello, this year is the anniversary of ${name} release ${years +1};

3.2.4 Array Type

// Add [] after the element type
let arr:number[]=[1,2];
//Or use array generics
let arr:Array<number>=[1,2];

3.2.5 tuple type

  • The meta-ancestor type is an array that represents the number and type of known elements. The types of elements need not be the same.

    let x:[string,number];
    x=['Angular',25];//Run normally
    x=[10,'Angular'];//Report errors
    console.log(x[0]); //Output Angular
    

3.2.6 Enumeration Types

  • Enumeration is an integer and familiar set that can be named. Enumeration types give meaningful names to the members of the set to enhance readability.

    enum Color {Red,Green,Blue};
    let c:Color=Color.Blue;
    console.log(c); //Output: 2
    
  • Enumeration default subscript is 0, you can manually modify the default subscript:

    enum Color {Red=2,Green,Blue=6};
    let c:Color=Color.Blue;
    console.log(c); //Output: 3
    

3.2.7 Arbitrary Value Types

  • An arbitrary value is a data type used by TypeScript for variables of unclear type at the time of programming:

    • When the value of a variable changes dynamically

      let x:any=1;//Numeric type
      x="I am a string"; //String type
      x=false;//Boolean type
      
    • When rewriting existing code, arbitrary values allow optional inclusion or removal of type checks at compilation time

      let x:any=4;
      x.ifItExists();//Correctly, the ifItExists method may exist at runtime, but it is not checked here.
      x.toFixed();//Correct
      
    • When defining arrays that store various types of data:

      let arrayList: any[]=[1,false,"fine"];
      arrayList[1]=100;
      

3.2.8 null and undefined

  • Enable strict null checks (- strict Null Checks) in TypeScript, null and undefined can only be assigned to void or its corresponding type:
    // Enable - stricNull Checks
    let x:number;
    x=1; // Running correctly
    x=undefined; // Running error
    x=null; // Running error

    • In the example above, variable x can only be a numeric type. If null or undefined may occur, you can use | to support multiple types.

      //Enable -- stricNull Checks
      let x:number;
      let y:number | undefined
      let z:number | null | undefined
      
      x=1; //Run correctly
      y=1; //Run correctly
      z=1; //Run correctly
      
      x=undefined; //Operation error
      y=undefined; //Run correctly
      z=undefined; //Run correctly     
      
      x=null; //Operation error
      y=null; //Operation error
      z=null; //Run correctly      
      
      x=y;//Operation error
      x=z;//Operation error
      y=x;//Run correctly
      y=z;//Operation error
      z=x;//Run correctly
      z=y;//Run correctly
      

3.2.9 void type

  • void means that there is no type

    • When the function has no return value, the return value type is void

      function hello():void{
      alert("Hello Angular");
      }

    • For callback functions with negligible return values, using void type is more complete than any value type.

      function func(foo:()=>void){
      let f=foo(); // Return value using function foo
      f.doSth(); // error reporting, void type does not exist doSth() method, at this time, any value type is replaced without error reporting.
      }

3.2.10 never type

  • Never is a subtype of other types (null and undefined), representing values that never appear.

    let x:never;
    let y:number;
    
    //Running error, number type cannot be converted to `never'type
    x=123;
    
    //Running correctly, the never type can be assigned to the never type
    x=(() => { throw new Error('exception occur')})();
    
    //Running correctly, the never type can be assigned to the numeric type
    y=(() => { throw new Error('exception occur')})();
    
    //A function with a return value of `never'can be an exception thrown case.
    function error(message:string):never{
        throw new Error(message);
    }
    
    //A function with a return value of `never'can be a termination point that cannot be executed
    function loop():never{
        while(true){
        }
    }
    

3.3 Declarations and Deconstructions

  • In TypeScript, support for declarations like var, let, and const

3.3.1 let declaration

  • let and var declare variables in a similar way:

    let hello="Hello Angular";
    
  • Variables declared by let are valid only in block-level scope:

    function f(input: boolean) {
      let a=100;
      if(input) {
        let b=a+1;//Run correctly
        return b;
      }
      return b;//Error, b is not defined
    }
    
  • Block-level scopes cannot be read or assigned before they are declared

    a++;//Error, use before declaration is illegal
    let a;
    
  • let is not allowed to be repeatedly declared

    var x=2;
    console.log(x+3);//Output: 5
    var x=3;
    console.log(x+3);//Output: 6
    
    let y=2;
    let y=3;//Error reporting, let declared variables cannot be declared multiple times in a scope
    
  • let declares a comparison of the following two functions:

    function funA(X) {
      let x=100;//Error reporting, x has been declared in the function reference declaration
    }
    
    //A new block-level scope composed of judgement conditions is added.
    function funB(condition,x) {
        if(condition){
            let x=100;//Run normally
            return x;
        }
        return x;
    }
    funB(false,0);//Return to 0
    funB(true,0);//Return to 100
    

3.3.2 const declaration

  • Const declarations are similar to let declarations, but const declarations are constants, constants cannot be reassigned, otherwise compilation errors will occur. However, if the defined constant is an object, the attribute values in the object can be reassigned:

    const CAT_LIVES_NUM=9;
    const kitty={
      name:"Aurora",
      numLives:CAT_LIVES_NUM
    };
    
    //error
    kitty={
      name:"Danielle",
      numLives:CAT_LIVES_NUM
    };
    
    kitty.name="Kitty";  //Correct
    kitty.numLives--;    //Correct
    

3.3.3 deconstruction

  • Deconstruction is to match a set of declared variables with the element values of an array or an object of the same structure, and assign the variables to the corresponding elements.

  • Array deconstruction

    let input=[1,2];
    let [first,second]=input;
    console.log(first); //Equivalent to input [0]:1
    console.log(second); //Equivalent to input [1]:2
    
    • It also acts on declared variables:

      [first,second]=[second,first];  //Variable exchange
      
    • Or acting on function parameters:

      function f([first,second]=[number,number]) {
        console.log(first+second);
      }
      f([1,2]); //Output 3
      
    • Use rest parameter syntax in array deconstruction

      let [first, ...rest]=[1,2,3,4];
      console.log(first);//Output 1
      console.log(rest);//Output: [2, 3, 4]
      
  • Object deconstruction

    let test={x:0,y:0,width:15,height:20};
    let {x,y,width,height}=test;
    console.log(x,y,width,height);//Output: 0, 10, 15, 20
    

3.4 function

3.4.1 Function Definition

  • Function declaration and expression are supported in TypeScript. The sample code is as follows:

// Writing of Function Declarations

function maxA(x:number,y:number):number {
  return x>y?x:y;
}

// Writing of Functional Expressions

let maxB=function(x:number,y:number):number {return x>y?x:y;}

3.4.2 Optional parameters

  • In TypeScript, every parameter of the called function must be passed on.

    function max(x:number,y:number):number {
      return x>y?x:y;
    }
    
    let result1=max(2);//Report errors
    let result2=max(2,4,7);//Report errors
    let result3=max(2,4);//Run normally
    
  • Typescript provides optional parameter syntax

    function max(x:number,y?:number):number {
      if(y){
         return x>y?x:y;
      } else {
        return x;
      }
    }
    
    let result1=max(2);//Run normally
    let result2=max(2,4,7);//Report errors
    let result3=max(2,4);//Run normally
    

3.4.3 Default parameters

  • Typescript also supports initializing default parameters, which are set by default if no value is passed or undefined:

    function max(x:number,y=4):number {
        return x>y?x:y;
    }
    
    let result1=max(2);//Run normally
    let result2=max(2,undefined);//Run normally
    let result3=max(2,4,7);//Report errors
    let result4=max(2,4);//Run normally
    
  • If the default parameter precedes the required parameter, the user must display undefined:

    function max(x=2,y: number):number {
        return x>y?x:y;
    }
    
    let result1=max(2);//Report errors
    let result2=max(undefined,4);//Run normally
    let result3=max(2,4,7);//Report errors
    let result4=max(2,4);//Run normally
    

3.4.4 Remaining parameters

  • When multiple parameters need to be manipulated at the same time, or when you don't know how many parameters will be passed in, you need to use the remaining parameters in Typescript.

    function sum(x:number,...restOfNumber: number[]):number {
        let result=x;
        for(let i=0;i<restOfNumber.length;i++){
            result+=restOfNumber[i];
        }
        return result; 
    }
    
    let result=sum(1,2,3,4,5);
    console.log(result);//Output: 15
    

3.4.5 Function Overload

  • Function overloading achieves multiple functions by providing multiple function type definitions for the same function.

    function css(config:{});
    function css(config:string,value:string);
    function css(config:any,valu?:any){
          if(typeof config==='string') {
            //...
          } else if(typeof config==='object') {
            //...
          }
    }
    

3.4.6 Arrow Function

let gift={
  gifts:["teddy bear","spiderman","dinosaur","Thomas loco","toy ricks","Transformers"],
  giftPicker:function () {
    return function () {
      let pickedNumber=Math.floor(Math.random()*6);
      return this.gifts[pickedNumber];
    }
  }
}
let pickGift=gift.giftPicker();
console.log("you get a :"+pickGift());//Uncaught TypeError: Cannot read property '1' of undefined
  • This in the giftPicker() function above is set to a window instead of a gift object, because there is no dynamic binding to this, so this points to a window object.

    let gift={
      gifts:["teddy bear","spiderman","dinosaur","Thomas loco","toy ricks","Transformers"],
      giftPicker:function () {
        return ()=> {
          let pickedNumber=Math.floor(Math.random()*6);
          return this.gifts[pickedNumber];
        }
      }
    }
    let pickGift=gift.giftPicker();
    console.log("you get a :"+pickGift());
    
  • The arrow function (=>) provided by the above code TypeScript solves this problem very well, and it binds this when the function is created.

3.5 category

Examples of Class 3.5.1

  • Traditional javascript programs use functions and prototype-based inheritance to create reusable "classes", which is not very friendly for developers accustomed to object-oriented programming. Class-based object-oriented programming can be supported in TypeScript.

  • Look at the following examples:

    class  Car{
      engine:string;
      constructor(engine:string){
        this.engine=engine;
      }
      drive(distanceInMeters:number=0){
        console.log(`A car runs ${distanceInMeters}m powered by` +this.engine);
      }
    }
    
    • The above declares a car class Car, which has three class members:

      • Class attribute engine
      • Constructor
      • drive() method
    • Where the class attribute engine can be accessed through this.engine

    • Instantiate a new car object and perform constructor initialization:

      let car =new Car("petrol");
      car.drive(100);//Output: A car runs 100m powered by petrol
      

3.5.2 Inheritance and Polymorphism

  • Encapsulation, inheritance and polymorphism are three characteristics of object-oriented.
  • In the example above, the behavior of the car is written into a class called encapsulation.
  • In TypeScript, inheritance can be easily implemented by using extends keywords:

    //Car class inherited from the previous article
    class MotoCar extends Car{
      constructor(engine: string) { super(engine); }
    }
    
    class Jeep extends Car {
      constructor(engine:string){
        super(engine);
      }
      drive(distanceInMeters:number=100){
        console.log("Jeep...");
        return super.drive(distanceInMeters);
      }
    }
    
    let tesla=new MotoCar("electricity");
    
    let landRover: Car=new Jeep("petrol"); //Realizing polymorphism
    
    tesla.drive();//Call the drive() method of the parent class
    
    landRover.drive(200);//Call drive() method of subclass
    
    • MotoCar and Jeep are subclasses of the base class Car, inheriting the parent class through extends
    • Subclasses can access attributes and methods of parent classes, or override methods of parent classes.
    • Jeep's drive() method overrides Car's drive() method, which has different functions in different classes, namely polymorphism.
    • Even if landRover is declared Car, it is still a subclass Jeep, and landRover. drive (200) calls the rewriting method in Jeep.
    • The derived class constructor calls super(), which executes the construction method of the base class.

3.5.3 modifier

  • There are three types of modifiers in a class:

    • Public
    • Private
    • Protected
  • public modifier

    • In TypeScript, each member defaults to'public'and is freely accessible:

      class  Car{
        public engine:string;
        public constructor(engine:string){
          this.engine=engine;
        }
        public drive(distanceInMeters:number=0){
          console.log(`A car runs ${distanceInMeters}m powered by` +this.engine);
        }
      }
      
  • private modifier

    • When a class member is marked private, it cannot be accessed outside the class. The sample code is as follows:

      class  Car{
        private engine:string;
        constructor(engine:string){
          this.engine=engine;
        }
      }
      
      new Car("petrol").engine;//Error reporting: The engine attribute is private and can only be accessed within the class
      
    • ES6 does not provide grammatical support for private attributes, but private attributes can be implemented through closures
  • protected modifier

    class  Car{
      protected engine:string;
      constructor(engine:string){
        this.engine=engine;
      }
      drive(distanceInMeters:number=0){
        console.log(`A car runs ${distanceInMeters}m powered by` +this.engine);
      }
    }
    
    class MotoCar extends Car{
      constructor(engine: string) { super(engine); }
      drive(distanceInMeters: number =50){
        super.drive(distanceInMeters);
      }
    }
    
    let tesla=new MotoCar("electricity");
    
    console.log(tesla.drive()); //Normal operation, output: A car runs 50m powered by electricity
    
    console.log(tesla.engine); //Report errors
    
    • Note that since engine is declared protected, it cannot be accessed externally, but it can still be accessed through its inheritance class MotoCar

3.5.4 parameter attributes

  • The parameter attribute is declared by adding an access qualifier (public, protected, and provate) to the constructor parameter.

    class  Car{
      constructor(protected engine:string){}
      drive(distanceInMeters:number=0){
        console.log(`A car runs ${distanceInMeters}m powered by` +this.engine);
      }
    }
    
    • In the constructor, the protected engine:string is used to create and initialize the engine member attributes, thus merging the declaration and assignment together.

3.5.5 Static Properties

  • Static members of a class exist on the class itself rather than on instances of the class.

    class Grid {
      static origin={x:0,y:0};
      constructor (public scale:number) {}
      calculateDistanceFromOrigin(point: {x:number;y:number;}){
        let xDist=(point.x-Grid.origin.x);
        let yDist=(point.y-Grid.origin.y);
        return Math.sqrt(xDist*xDist+yDist*yDist)/this.scale;
      }
    }
    
    let grid1= new Grid(1.0);
    let grid2= new Grid(5.0);
    console.log(grid1.calculateDistanceFromOrigin({x:10,y:10})); //Output: 14.142135623730951
    console.log(grid2.calculateDistanceFromOrigin({x:10,y:10})); //Output: 2.8284271247461903
    

3.5.6 abstract classes

  • TypeScript has the concept of abstract classes, which are the base classes inherited by other classes and cannot be instantiated directly. Abstract classes must contain some abstract methods, but also can contain non-abstract members. Abstract keywords are used to define abstract classes and methods.

    abstract class Person {
      abstract speak():void;//Must be implemented in a derived class
      walking(): void {
        console.log('walking on the road');
      }
    
      class Male extends Person {
        speak(): void{
          console.log('How are you?');
        }
      }
    }
    
    let person:Person;  //Create an abstract class reference
    person=new Person(); //Error reporting: cannot create abstract class instances
    person=new Male();   //Create a Male instance
    person.speak();
    person.walking();
    

3.6 module

3.6.1 overview

  • Modules are executed in their own scope, not in the global scope, which means that variables, functions and classes defined in a module are not visible outside the module unless they are explicitly exported using export. Instead, they must be imported through import.
  • In Angular, common module loaders are System JS and Webpack

3.6.2 Module Export Mode

  • Export declaration

    export const COMPANY="GF";//Derived variables
    
    export interface IdentityValidate{  //Export interface
        isGfStaff(s: string): boolean;
    }
    
    export class ErpIdentityValidate implements IdentityValidate { //Derived class
        isGfStaff(erp: string) {
            return erpService.contains(erp);  //Judge whether it is an internal employee or not
        }
    }
    
  • Export statement (when we need to rename the exported module, we use the export statement)

    class ErpIdentityValidate implements IdentityValidate { //Derived class
        isGfStaff(erp: string) {
            return erpService.contains(erp);  
        }
    }
    
    export { ErpIdentityValidate };
    export { ErpIdentityValidate as GFIdentityValidate };
    
  • Module wrapping (modifying and expanding existing modules and exporting them for other modules to call)

    //Export the original validator, but rename it   
    export { ErpIdentityValidate as RegExpBasedZipCodeValidator} from "./ErpIdentityValidate";
    

3.6.3 Module Import Mode

  • Module import corresponds to module export, and import keywords can be used to import external modules that the current module depends on. There are several ways to import:

    • Import module

      import { ErpIdentityValide } from "./ErpIdentityValidate";
      let erpValide = new ErpIdentityValidate();
      
    • Alias import

      import { ErpIdentityValide as ERP } from "./ErpIdentityValidate";
      let erpValide = new ErpIdentityValidate();
      
      • The whole module can be imported by aliases, and the whole module can be imported into a variable through which the export part of the module can be accessed:

        import * as validator from "./ErpIentityValidate";
        let myValidate= new validator.ErpIdentityValidate();
        

Default export of 3.6.4 module

  • Modules can use default keywords to implement the default export function, each module can have a default export.

    • Default export class

      //ErpIdentityValidate.ts
      export default class ErpIdentityValidate implements IdentityValidate {
          isGfStaff(erp:string){
              return erpService.contains(erp);
          }
      }
      
      //test.js
      import validator from "./ErpIdentityValidate";
      let erp = new validator();
      
    • Default export function

      // nameServiceValidate.ts
      
      export default function (s: string) {
          return nameService.contains(s);
      }
      //test.js
      import validator from "./nameValidate";
      let name = "Angular";
      
      //Using Derived Functions
      console.log(`"${nmae}" ${ validate(name) ? "matches" : " does not match"}`);
      
    • Default export value

      // constantService.ts
      export default "Angular";
      
      //test.ts
      import name from "./constantService";
      console.log(name);//"Angular"
      

3.6.4 Module Design Principles

  • Export as much as possible at the top level

    //ClassTest.ts
    export default class ClassTest {
      // ...
    }
    
    //FuncTest.ts
    export default function FuncTest() {
      // ...
    }
    
    //Test.ts
    import ClassTest from "./ClassTest";
    import FuncTest from "./FuncTest";
    
    let C=new ClassTest();
    FuncTest();
    
    • When multiple objects are returned, the top-level export can be used, and the name of the imported object can be clearly listed when invoking:

      //MouduleTest.ts
      export class ClassTest() {
        // ...
      }
      
      export FuncTest() {
        // ...
      }
      
      //Test.ts
      import { ClassTest,FunctTest} from "./ModuleTest";
      
      let C=new ClassTest();
      FuncTest();
      
    • List the imported names explicitly

      • When importing, specify the name of the imported object as clearly as possible, so that as long as the interface remains unchanged, the invocation method can be unchanged, thus reducing the coupling between import and export templates, and achieving Interface-oriented programming.

        import { ClassTest,FunctTest} from "./ModuleTest";
        
    • Export using namespace schema

      // MyLargeModule.ts
      export class Dog {/* ... */ }
      export class Cat {/* ... */ }
      export class Tree {/* ... */ }
      export class Flower {/* ... */ }
      
      //Consumer.ts
      import* as myLargeModule from "./MyLargeModule.ts";
      let x= new myLargeModule.Dog();
      
    • Extension using modular packaging

      • We may often have to expand the functions of a module. The recommended solution is not to change the original object, but to export a new object to provide new functions. The sample code is as follows:

        // ModuleA.ts
        
        export class ModuleA {
            constructor() {/* ... */}
            sayHello() {
                // ...
            }
        }
        
        
        // ModuleB.ts
        import { ModuleA } from "./ModuleA.ts"
        class ModuleB extends ModuleA {
          constructor() { super(); /* ... */ }
          //Adding new methods
          sayHi() {
            // ...
          }
        }
        
        //Test.ts
        import { ModuleA } from "./ModuleB";
        
        let C=new ModuleA();
        

3.7 interface

3.7.1 overview

  • The use of the TypeScript interface is similar to that of Java

3.7.2 Attribute Type Interface

  • In TypeScript, use the interface keyword to define the interface

    interface FullName {
      firstName: string;
      secondName: string;
    }
    
    function printLable(name: FullName) {
      console.log(name.firstName + " "+name.secondName);
    }
    
    let myObj = {age:10,firstName:"Jim",secondName:"Raynor"};
    printLable(myObj);
    
    • Objects passed to the printLable() method can be "formally" satisfied with the requirements of the interface
    • The interface type checker does not check the order of attributes, but ensures that the corresponding attributes exist and the type matches.
  • TypeScript also provides optional attributes

    interface FullName {
      firstName: string;
      secondName?: string;
    }
    
    function printLable(name: FullName) {
      console.log(name.firstName + " "+name.secondName);
    }
    
    let myObj = {firstName:"Jim"};  //secondName is an optional property that can not be passed on
    printLable(myObj);  //Output: Jim undefined
    

3.7.3 Function Type Interface

  • When defining the function type interface, we need to clearly define the parameter list and return value type of the function, and each parameter in the parameter list should have the parameter name and type:

    interface encrypt {
      (val:string,salt:string):string
    }
    
  • How to use the function type interface:

    let md5: encrypt;
    md5=function (val:string,salt:string) {
      console.log("origin value:" +val);
      let encryptValue =doMd5(val,salt);//doMd5 is just a mock method
      console.log("encrypt value:" +encryptValue);
      return encryptValue;
    }
    let pwd =md5("password","Angular");
    
    • Interfaces of function types need to be noted:
      • The number of parameters used should be the same as the parameters defined by the interface, the data type of the corresponding position variables should be the same, and the parameter names can be different.
      • Quantitative return value of a function: The return value type of a function should be the same as the return value type defined by the interface.

3.7.4 Indexable Type Interface

  • Get the return value of the specified type through a specific index:

    interface UserArray {
      [index: number]: string;
    }
    
    
    interface UserObject {
      [index: string]: string;
    }
    
    let userArray: UserArray;
    let UserObject: UserObject;
    
    userArray =["Zhang San","Li Si"];
    userObject =["name","Zhang San"];
    
    console.log(userArray[0]);  //Output: Zhang San
    console.log(userObject["name"]);  //Output: Zhang San
    
  • Even if indexed by numeric type, javascript eventually converts it to string type and then to index the object's

    console.log(userArray[0]);  //Output: Zhang San
    console.log(userArray["0"]);  //Output: Zhang San
    

Class 3.7.5 Type Interface

  • The class type interface is used to specify the content of a class. The sample code is as follows:

    interface Animal {
      name: string;
    }
    
    
    class Dog implements Animal {
        name: string;
        constructor(n: string) {}
    }
    
    • We can describe a method in the interface and implement its functions in the class, just like the setName method below.

      interface Animal {
       name: string;
       setName(n: string): void;
      }
      class Dog implements Animal {
          name: string;
          setName(n: string) {
              this.name=n;
          }
          constructor(n: string) {}
      }
      

3.7.6 Interface Extension

  • Like classes, interfaces can also be extended by copying members from one interface to a page, which makes it more flexible to split interfaces into reusable templates:

    interface Animal {
        eat(); void;
    }
    
    interface Person extends Animal {
        talk(); void;
    }
    
    class Programmer {
        coding():void{
            console.log('wow,TypeScript is the best language');
        }
    }
    
    class ITGirl extends Programmer implements Person {
        eat() {
            console.log('animal eat');
        }
    
        talk(){
          console.log('person talk');
        }
    
        coding():void {
         console.log('I am girl,but i like coding.');
        }
    }
    
    let itGirl =new ITGirl(); //Modules can be reused more flexibly by combining integration classes to achieve interface extension
    itGirl.coding();
    

3.8 Decorator

3.8.1 overview

  • Decorators are special types of declarations that can be attached to class declarations, methods, attributes, or parameters.
  • The decorator is followed by a function name by the @ symbol
  • Decorators are used to decorate the attached subject and add additional behavior.

    //Method Decorator
    
    declare type MethodDecorarot =<T>(target: Object,propertyKey: string | symbol,
        descriptor: TypedPropertyDescriptor<T>)=> TypedPropertyDescriptor<T> | void;
    
    
    //Class decorator
    declare type ClassDecorator =<TFunction extends Function>(target: TFunction) => TFunction | void;
    
    
    //Parametric Decorator
    declare type ParameterDecorator = ( target: Object, propertyKey: string | symbol,parameterIndex: number) => void;
    
    //Attribute Decorator
    declare type PropertyDecorator = ( target: Object, propertyKey: string | symbol) => void;
    

3.8.2 Method Decorator

  • Method decorator is declared before a method (next to the method declaration), which is applied to the attribute descriptor of the method and can be used to monitor, modify, or replace the method definition. The declaration of the method decorator is as follows:

    declare type MethodDecorator = <T>(target: Object,propertyKey: string | symbol,
        descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
    

    The method decorator expression is called at run time as a function, passing in the following three parameters:

    • target: The prototype object of a class
    • ProperrtyKey: The name of the method
    • descriptor: Description of member attributes
  • Among them, the type of descriptor is TypedProperty Descriptor, which is defined in TypeScript as follows:

    interface TypedPropertyDescriptor<T> {
        enumerable?: boolean; //Is it traversable
        configurable?: boolean; //Whether the property description can be changed or whether the property can be deleted
        writable?: boolean; //Is it modifiable
        value?: T; //Attribute value
        get?: ()=>; //Accessor function for properties (getter)
        set?: (value: T) => void;//Setter function of attributer
    }
    
  • Method Decorator example:

    class TestClass {
        @log
        testMethod(arg: string) {
            return "logMsg: " +arg;
        }
    }
    
    • The following is the implementation of the method decorator @log:

      function log(target: Object,propertyKey: string,descriptor:
          TypedPropertyDescriptor<any>) {
          let origin =descriptor.value;
          descriptor.value=function(...args: any[]) {
              console.log("args: "+JSON.stringify(args)); //Before calling
              let result =origin.apply(this,args);    //Calling method
              console.log("The result-" + result);    //After calling
              return result;     //Return result
          }
      
          return descriptor;
      
      }
      
      • The following code can then be used for testing:

        new TestClass().testMethod("test method decorator");
        
      • The results are as follows:

        args: ["test method decorator"]
        The result-logMsg: test method decorator
        
      • When the method decorator @log is called, it prints the log information.

Class 3.8.3 Decorators

  • Class decorators are declared before a class is declared. They are applied to class constructors and can be used to monitor, modify, or replace class definitions. They are defined in TypeScript as follows:

    declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
    
    • As shown above, the constructor of a class is its only parameter. Class decorators are called at runtime as functions.
    • If the class decorator returns a value, it replaces the class declaration in the constructor. Here is an example of using class decorator (@Component) to apply to the Person class. The sample code is as follows:

      @Component({
          selector: 'person',
          template: 'person.html'
      })
      class Person {
       constructor(
          public firstNmae:string,
          public secondName:string
       ){}
      }
      
      • The definition of class decorator @Component is as follows:

        function Component(component) {
            return (target:any) => {
                return componentClass(target,component);
            }
        }
        
        // Implementation of CompoonentClass
        
        function componentClass(target:any,component?:any):any {
            var original =target;
            function construct(constructor,args){ //Processing prototype chains
                let c:any = function () {
                    return constructor.apply(this,args);
                };
            c.prototype =constructor.prototype;
            return new c;
            }
        
        
            let f:any = (...args) => {
                console.log("selector:" + component.selector);
                console.log("template:" + component.template);
                console.log(`Person: ${original.name}(${JSON.stringify(args)})`);
                return construct(original,args);
            };  
        
            f.prototype =original.prototype;    
             retuen f;  //Return constructor
        }
        
      • The following code can then be used for testing:

        let p = new Person("Angular","JS");
        
      • The results are as follows:

        selector:person
        template:person.html
        Person: Person(["Angular","JS"])
        
      • The above code seems a bit cumbersome, because we have returned a new constructor and we have to deal with the original prototype chain ourselves.

3.8.4 Parameter Decorator

  • A parameter decorator is declared before a parameter is declared. It is used for class constructors or method declarations. The parameter decorator is called at runtime as a function, defined as follows:

    declare type ParameterDecorator =(target: Object,propertyKey: string | symbol,parameterIndex: number) => void;
    
  • As mentioned above, it contains three parameters:

    • target: For static members, it is a constructor of a class, and for instance members, it is a prototype object of a class.
    • ProperrtyKey: parameter name.
    • parameterIndex: Index of parameters in the list of function parameters.
  • Here is a simple example of a parametric decorator:

    class userService {
        login(@inject name: string) {}
    
    }
    
    // @ Implementation of Inj Decorator
    function inject (target: any,propertyKet: string | symbol,parameterIndex: number) {
        console.log(target); //userService prototype
        console.log(propertyKey); 
        console.log(parameterIndex); 
    }
    
     // The results are as follows:
    Oject
    login
    0
    

3.8.5 Attribute Decorator

  • Attribute Decorator

    • Attribute decorators are defined as follows:

      declare type PropertyDecorator =(target: Object,propertyKey: string | symbol) => void;
      
    • As mentioned above, it contains two parameters:

      • target: For static members, it is a constructor of a class, and for instance members, it is a prototype object of a class.
      • ProperrtyKey: Property name

3.8.6 Decorator Combination

  • TypeScript supports multiple decorators and applies them to one declaration at the same time:

    • Writing from left to right:

      @decoratorA @decoratorB param
      
    • Writing from top to bottom:

      @decoratorA
      @decoratorB
      functionA
      
  • In TypeScript, when multiple decorators are applied to the same declaration, the following steps are performed:

    • The decorator function is executed from left to right (top to bottom) and the result is returned.
    • The return result is called as a function from left to right (top to bottom).
  • Following is an example of two class decorator composite applications. Note the execution sequence shown by the output results. The sample code is as follows:

    function Component (component) {
        console.log('selector: '+component.selector);
        console.log('template: '+component.tempalte);
        console.log('component init');
        return (target: any) => {
            console.log('component call');
            return target;
        }
    }
    function Directive (directive) {
        console.log('directive init');
        return (target: any) => {
            console.log('directive call');
            return target;
        }
    }
    
    @Component({
        selector: 'person',
        template: 'person.html'
    })
    @Directive()
    class Person {
    
    }
    
    let p= new Person();
    
  • The results are as follows:

    selector: person    
    template: undefined 
    component init      
    directive init      
    directive call      
    component call      
    

3.9 generic

  • In practical development, the API we define not only needs to consider whether the function is sound, but also needs to consider its reusability. More often, it needs to support non-specific data types, and generics are used to achieve this effect.
  • The following minimum heap algorithm needs to support both numeric and string types. It can be achieved by changing the set type to any value type. But this is equivalent to giving up type checking. We hope that the return type needs to be consistent with the parameter type. The sample code is as follows:

    class MinHeap<T> {                                                                                             
        list: T[]=[];                                                                                              
    
        add(element: T): void {                                                                                    
            //Here we compare the sizes and put the minimum at the head of the array                                                                                 
        }                                                                                                          
    
        min():  T {                                                                                                
            return this.list.length ? this.list[0] : null;                                                         
        }                                                                                                          
    }                                                                                                              
    
    let heap1 =new MinHeap<number>();                                                                              
    heap1.add(3);                                                                                                  
    heap1.add(5);                                                                                                  
    console.log(heap1.min());                                                                                      
    
    let heap2 =new MinHeap<string>();                                                                              
    heap2.add('a');                                                                                                
    heap2.add('c');                                                                                                
    console.log(heap2.min());
    
  • Generics also support functions

    function zip<T1,T2> (l1: T1[], l2: T2[]):[T1,T2][] {             
        let len =Math.min(l1.length, l2.length);                     
        let ret=[];                                                  
        for (let i=0;i<len;i++){                                     
            ret.push([l1[i], l2[i]]);                                
        }                                                            
        return ret;                                                  
    }                                                                
    
    console.log(zip<number, string>([1,2,3],['Jim','Sam','Tom'])); 
    

3.10 TypeScript Periphery

3.10.1 Compile Configuration Files

  • Configuration files can reduce tedious command line parameters and improve development efficiency.

3.10.2 Declaration Document

Posted by newcastle_unite on Wed, 03 Apr 2019 09:18:32 -0700