Typescript - Advanced

Posted by dieselmachine on Mon, 21 Feb 2022 13:39:01 +0100

object-oriented
That is, the operations in the program need to be completed through objects, for example:

  • To operate the browser, use the window object
  • The document object is used to manipulate the web page
  • To operate the console, use the console object

In the program, all objects are divided into two parts: data and function. There is no more comparison here

1. class

If you want to be object-oriented and manipulate objects, you must first have objects, so the next problem is how to create objects. To create an object, you must first define a class. The so-called class can be understood as the model of the object. In the program, you can create an object of a specified type according to the class. For example, you can create a human object through the Person class, a Dog object through the Dog class, and a Car object through the Car class. Different classes can be used to create different objects.

(1) Define class

  class Class name {
    	Attribute name: type;
    	
    	constructor(parameter: type){
    		this.Attribute name = parameter;
    	}
    	
    	Method name(){
    		....
    	}
    
    }

For example:

  class Person{
        name: string;
        age: number;
    
        constructor(name: string, age: number){
            this.name = name;
            this.age = age;
        }
    
        sayHello(){
            console.log(`Hello, I'm ${this.name}`);
        }
    }
  • Use class:
    • const p = new Person('viagra', 27);
      p.sayHello();
      

2. Object oriented features

  • encapsulation
    • An object is essentially a container for attributes and methods. Its main function is to store attributes and methods, which is called encapsulation
    • By default, the attributes of objects can be modified arbitrarily. In order to ensure the security of data, the permissions of attributes can be set in TS
    • Read only attribute (readonly):
      • If you add a readonly when declaring a property, the property becomes read-only and cannot be modified
    • Attributes in TS have three modifiers:
      • public (default), which can be modified in classes, subclasses and objects
      • protected, which can be modified in classes and subclasses
      • private, which can be modified in the class
    • Example:
      • public
        • class Person{
              public name: string; // Writing or not writing anything is public
              public age: number;
          
              constructor(name: string, age: number){
                  this.name = name; // Can be modified in class
                  this.age = age;
              }
          
              sayHello(){
                  console.log(`Hello, I'm ${this.name}`);
              }
          }
          
          class Employee extends Person{
              constructor(name: string, age: number){
                  super(name, age);
                  this.name = name; //Can be modified in subclass
              }
          }
          
          const p = new Person('Uncle Wei', 27);
          p.name = 'Zhu Bajie';// It can be modified by objects
          
      • protected
        • class Person{
              protected name: string;
              protected age: number;
          
              constructor(name: string, age: number){
                  this.name = name; // Can be modified
                  this.age = age;
              }
          
              sayHello(){
                  console.log(`Hello, I'm ${this.name}`);
              }
          }
          
          class Employee extends Person{
          
              constructor(name: string, age: number){
                  super(name, age);
                  this.name = name; //Can be modified in subclass
              }
          }
          
          const p = new Person(Grandpa Wei', 27);
          p.name = 'Your father';// Cannot modify
          
      • private
        • class Person{
              private name: string;
              private age: number;
          
              constructor(name: string, age: number){
                  this.name = name; // Can be modified
                  this.age = age;
              }
          
              sayHello(){
                  console.log(`Hello, I'm ${this.name}`);
              }
          }
          
          class Employee extends Person{
          
              constructor(name: string, age: number){
                  super(name, age);
                  this.name = name; //Cannot modify in subclass
              }
          }
          
          const p = new Person('viagra', 127);
          p.name = 'Your father';// Cannot modify
          
    • Attribute accessor
      • For some properties that you do not want to modify arbitrarily, you can set them to private
      • Setting it to private directly will make it impossible to modify its properties through the object
      • We can define a set of methods to read and set properties in a class. The properties read or set on properties are called property accessors
      • The method of reading properties is called setter method, and the method of setting properties is called getter method
      • Example:
        • class Person{
              private _name: string;
          
              constructor(name: string){
                  this._name = name;
              }
          
              get name(){
                  return this._name;
              }
          
              set name(name: string){
                  this._name = name;
              }
          
          }
          
          const p1 = new Person('viagra');
          console.log(p1.name); // Read the name attribute through getter
          p1.name = 'Your father'; // Modify the name attribute through setter
          
    • Static properties
      • Static properties (Methods), also known as class properties. Using static attributes can be used directly through classes without creating instances
      • Static attributes (Methods) start with static
      • Example:
        • class Tools{
              static PI = 3.1415926;
              
              static sum(num1: number, num2: number){
                  return num1 + num2
              }
          }
          
          console.log(Tools.PI);
          console.log(Tools.sum(123, 456));
          
    • this
      • In the class, use this to represent the current object
  • inherit
    • Inheritance is another feature of object-oriented
    • Inheritance allows you to introduce properties and methods from other classes into the current class
      • Example:
        • class Animal{
              name: string;
              age: number;
          
              constructor(name: string, age: number){
                  this.name = name;
                  this.age = age;
              }
          }
          
          class Dog extends Animal{
          
              bark(){
                  console.log(`${this.name}Barking!`);
              }
          }
          
          const dog = new Dog('Wangcai', 4);
          dog.bark();
          
    • Through inheritance, you can extend a class without modifying it
    • rewrite
      • When inheritance occurs, if the method in the subclass will replace the method with the same name in the parent class, this is called method override
      • Example:
        • class Animal{
              name: string;
              age: number;
          
              constructor(name: string, age: number){
                  this.name = name;
                  this.age = age;
              }
          
              run(){
                  console.log(`In the parent class run method!`);
              }
          }
          
          class Dog extends Animal{
          
              bark(){
                  console.log(`${this.name}Barking!`);
              }
          
              run(){
                  console.log(`In subclasses run Method, which overrides the run method!`);
              }
          }
          
          const dog = new Dog('Wangcai', 4);
          dog.bark();
          
        • super can be used in subclasses to complete the reference to the parent class
    • abstract class
      • An abstract class is a class that is specifically used to be inherited by other classes. It can only be inherited by other classes and cannot be used to create instances
      • abstract class Animal{
            abstract run(): void;
            bark(){
                console.log('Animals are barking~');
            }
        }
        
        class Dog extends Animals{
            run(){
                console.log('The dog is running~');
            }
        }
        
      • Methods starting with abstract are called abstract methods. Abstract methods have no method body and can only be defined in abstract classes. Abstract methods must be implemented when inheriting abstract classes

3. Interface

The function of an interface is similar to that of an abstract class. The difference is that all methods and properties in the interface have no real values. In other words, all methods in the interface are abstract methods. The interface is mainly responsible for defining the structure of a class. The interface can limit the interface of an object. The object can match the interface only when it contains all the attributes and methods defined in the interface. At the same time, a class can implement the interface. When implementing the interface, all attributes in the interface should be protected in the class.

  • Example (check object type):

    • interface Person{
          name: string;
          sayHello():void;
      }
      
      function fn(per: Person){
          per.sayHello();
      }
      
      fn({name:'Sun WuKong', sayHello() {console.log(`Hello, I am ${this.name}`)}});
      
  • Example (Implementation)

    • interface Person{
          name: string;
          sayHello():void;
      }
      
      class Student implements Person{
          constructor(public name: string) {
          }
      
          sayHello() {
              console.log('Hello, I'm'+this.name);
          }
      }
      

4. Generic

When defining a function or class, in some cases, the specific type to be used cannot be determined (the type of return value, parameter and attribute cannot be determined), and then the generic type can play a role.

  • for instance:
    • function test(arg: any): any{
      	return arg;
      }
      
    • In the above example, the test function has an uncertain parameter type, but when it can be determined, the type of its return value and the type of the parameter are the same. Because the type is uncertain, any is used for both the parameter and the return value, but it is obviously inappropriate to do so. First, using any will turn off the type check of TS, Secondly, this setting cannot reflect that the parameter and return value are of the same type
    • Use generics:
    • function test<T>(arg: T): T{
      	return arg;
      }
      
    • Here is the generic type. T is the name we give this type (not necessarily T). After setting the generic type, we can use t in the function to represent this type. So generics are actually easy to understand, which means a type.
    • So how to use the above function?
      • Method 1 (direct use):
        • test(10)
          
        • When in use, parameters can be passed directly, and the type will be automatically inferred by TS, but sometimes the following methods need to be used when the compiler cannot infer automatically
      • Mode 2 (specify type):
        • test<number>(10)
          
        • You can also specify generics manually after a function
    • Multiple generics can be specified at the same time, separated by commas:
      • function test<T, K>(a: T, b: K): K{
            return b;
        }
        
        test<number, string>(10, "hello");
        
      • When using generics, you can use generics as a common class
    • Generics can also be used in classes:
      • class MyClass<T>{
            prop: T;
        
            constructor(prop: T){
                this.prop = prop;
            }
        }
        
    • In addition, you can also constrain the scope of generics
      • interface MyInter{
            length: number;
        }
        
        function test<T extends MyInter>(arg: T): number{
            return arg.length;
        }
        
      • Use T extensions MyInter to indicate that the generic type T must be a subclass of MyInter. It is not necessary to use interface classes. The same applies to abstract classes.

Topics: Javascript Front-end TypeScript ts