function

Functions are an extremely important part of JavaScript, and we’ve always called them first-class citizens, the basic building blocks of any application.

Functions

Like JavaScript, TypeScript creates named and anonymous functions.

  • There are two ways to create a function in JavaScript:

    // Name the function
    function add(x,y){
        return x + y;
    };
    
    // Anonymous function
    let add2 = function(x,y){
        return x + y;
    };
    Copy the code

TypeScript function types

  • Annotation type

    Examples of the two ways in which JavaScript can create functions are as follows:

    // Name the function
    function add(x:number,y:number) :number{
        return x + y;
    };
    
    // Anonymous function
    let add2 = function(x:number,y:number) :number{
        return x + y;
    };
    Copy the code

    You can see from the code that we can add a type to each parameter as well as to the return value.

  • Required, optional, default, and indefinite parameters

    • Required parameters

      In TypeScript, the number of arguments assigned to a function must match the number of arguments the function expects to pass in, or an error will be returned

      function Person(name:string,age:number){
          return name + '有' + age + ', '
      }
      
      let person1 = Person('jack')// Two parameters are expected, but the function only gets one
      let person2 = Person('jack'.18.'Play basketball')// Two parameters are expected, but the function gets three
      let Person3 = Person('jack'.18)//right
      Copy the code
    • Optional parameters

      In JavaScript, each parameter in a function is optional and the user can reserve it as needed. When we need an optional parameter in TypeScript, we add a ** after the parameter we want to make optional. Is an optional parameter **.

      function Person(name:string,age:number,hobby? :string){
          return name + '有' + age + ', '+'like' + hobby; 
      }
      let result1 = Person("Bob");// It prompts you to expect 2-3 arguments, but the function only gets one
      let result2 = Person("Bob".18."Play basketball");//right
      let result3 = Person("Bob".18);//right
      Copy the code
    • The default parameters

      In TypeScript, we can set a value for a function parameter and assign it a value if the user does not provide a parameter or if the user passes undefined to it. We call these parameters default parameters.

      function Person(name:string,age:number,hobby='Play basketball'){
          return name + '有' + age + ', '+'like' + hobby; 
      }
      let result1 = Person("Bob");// It prompts you to expect 2-3 arguments, but the function only gets one
      let result2 = Person("Bob".18."Play basketball");//right
      let result3 = Person("Bob".18);//right
      let result4 = Person("Bob".18."Play football");//right
      let result5 = Person("Bob".18.undefined);//right
      Copy the code
    • Uncertain parameters

      Unlike required, optional, and default parameters, which are all discussed one parameter at a time, indefinite parameters are composed of multiple parameters as a group. In JavaScript we can use arguments for indefinite arguments, whereas in TypeScript we can use an ellipsis (…). To indicate that the parameter is an indefinite parameter.

      function Person(name:string. hobby:string[]){
          return name +'like' + hobby.join(' '); 
      }
      let result2 = Person("Bob"."Play basketball".'Play football'.'Play badminton');//right
      let result3 = Person("Bob".18."Play basketball".'Play football'.'Play badminton');
      // Parameters of type "number" cannot be assigned to parameters of type "string"
      Copy the code

this

Learning how to use this in JavaScript is an important skill. Since TypeScript is a superset of JavaScript, TypeScript developers also need to learn how to use this correctly in TypeScript.

  • This and the arrow function

    In JavaScript, the fact that this is a variable that is set when a function is called makes it a very powerful and flexible feature, but at the expense of the execution context, which can cause this pointing problems when returning a function or passing a function as an argument, as in the following example:

    let deck = {
      suits: ["Red heart"."Spade"."Sucks"."Square"].cards: Array(52),
      createCardPicker: function () {
        return function () {
          let pickedCard = Math.floor(Math.random() * 52);
          let pickedSuit = Math.floor(pickedCard / 13);
          console.log(this);// This is undefined
          return { suit: this.suits[pickedSuit], card: pickedCard % 13}; }; }};let cardPicker = deck.createCardPicker();
    let pickedCard = cardPicker();'this' has an implicitly typed attribute, so the annotation does not have any type
    console.log("card: " + pickedCard.card + " of " + pickedCard.suit);
    Copy the code

    We can solve the pointing problem of this by using ES6’s arrow syntax to ensure that this is bound to the correct location, as follows:

    let deck = {
      suits: ["Red heart"."Spade"."Sucks"."Square"].cards: Array(52),
      createCardPicker: function () {
        return () = > {
          let pickedCard = Math.floor(Math.random() * 52);
          let pickedSuit = Math.floor(pickedCard / 13);
    
          return { suit: this.suits[pickedSuit], card: pickedCard % 13}; }; }};let cardPicker = deck.createCardPicker();
    let pickedCard = cardPicker();
    
    console.log("card: " + pickedCard.card + " of " + pickedCard.suit);
    Copy the code
  • This parameter

    The above example uses arrow syntax to solve the pointing problem of this, but this is still of type any. We can solve the problem by providing an explicit this argument as follows:

    interface Card {
      suit: string;
      card: number;
    }
    
    interface Deck {
      suits: string[];
      cards: number[];
      createCardPicker(this: Deck): () = > Card;
    }
    
    let deck: Deck = {
      suits: ["Red heart"."Spade"."Sucks"."Square"].cards: Array(52),
      createCardPicker: function (this: Deck) {
        return () = > {
          let pickedCard = Math.floor(Math.random() * 52);
          let pickedSuit = Math.floor(pickedCard / 13);
    
          return { suit: this.suits[pickedSuit], card: pickedCard % 13}; }; }};let cardPicker = deck.createCardPicker();
    let pickedCard = cardPicker();
    
    console.log("card: " + pickedCard.card + " of " + pickedCard.suit);
    Copy the code

    By providing an explicit this argument, we now know that this is now a Deck type, not an any type.

overloading

Describe a function that produces different results when passed different arguments to facilitate type checking:

let suits = ["hearts"."spades"."clubs"."diamonds"];

function pickCard(x: { suit: string; card: number} []) :number;
function pickCard(x: number) :{ suit: string; card: number };
function pickCard(x: any) :any {
  if (typeof x == "object") {
    let pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
  }
  // Otherwise just let them pick the card
  else if (typeof x == "number") {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13}; }}let myDeck = [
  { suit: "diamonds".card: 2 },
  { suit: "spades".card: 10 },
  { suit: "hearts".card: 4},];let pickedCard1 = myDeck[pickCard(myDeck)];
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(12);
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
Copy the code

This example has only two overloads: one for an object and one for a number. If the pickCard() function is called with a different type of argument, it will cause a compilation error.

class

The definition of a class

Class is the basis of information encapsulation in object-oriented programming. Class is a user-defined reference data type, also known as class type. Each class contains data descriptions and a set of functions that manipulate data or pass messages. Instances of classes are called objects.

Class properties and methods

A class can generally contain static attributes, member attributes, constructors, static methods, and member methods as follows:

class Person{
  // Static attributes
  static names:string = 'jack';
  // Member attributes
  age:string;
  // constructor
  constructor(message:string){
    this.age = message;
  };
  // static function
  static getName(){
    return this.names
  }
  // Member functions
  getAge(){
    return `${Person.names}There are nowThe ${this.age}At the age of `}}let jackAge = new Person('16');
console.log(jackAge.getAge());
console.log(Person.getName());
Copy the code

As you can see from the above code, static members are not visible on the instance but on the class itself, which means that when we need to access the static member, we need to call the static member from the class itself.

inheritance

Inheritance means that a subclass inherits the characteristics and behaviors of its parent class, so that the subclass has the attributes and methods of its parent class. It is one of the most basic methods to extend the parent class. The code is as follows:

class Animal {
  name:string;
  constructor(newName:string){
    this.name = newName;
  }
  move(distance: number = 0) {
    console.log(`The ${this.name} moved ${distance}m.`); }}class Dog extends Animal {
  bark() {
    console.log("Woof! Woof!"); }}const dog = new Dog('Dog');
dog.move(10);
dog.bark();
console.log(dog.name);
Copy the code

ECMAScript private fields

In Typescript3.8, Typescript supports the syntax for ECMAScript private fields, as shown below:

class Person {
  #name: string;
  constructor(theName: string) {
    this.#name = theName; }}new Person("jack").#name;
//Property '#name' is not accessible outside class 'Person' because it has a private identifier.
Copy the code

#name is declared, but its value is never read. Private fields have the following characteristics:

  • Private fields start with a “#” character
  • A private field only applies to the class it contains
  • Private fields cannot be accessed outside of their containing classes and are not detected

Typescript private fields

Typescript also has its own method (private) to mark members as private fields, another method that cannot be accessed from outside the containing class:

class Person {
  private name: string;
  constructor(name: string) {
    this.name = name; }}class Jack extends Person {
  private department: string;
  constructor(name: string, department: string) {
  super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return `Hello, my name is The ${this.name} and I work in The ${this.department}. `;
  }//Property 'name' is private and only accessible within class 'Person'
}

let howard = new Jack("Jack"."Technical Department");
console.log(howard.getElevatorPitch());
console.log(Jack.name);
console.log(Person.name)
console.log(howard.name);
//Property 'name' is private and only accessible within class 'Person'
Copy the code

There is a protected behavior in Typescript that is similar to the private behavior, except that members declared in protected can be queried by derived classes as follows:

class Person {
  protected name: string;
  constructor(name: string) {
    this.name = name; }}class Jack extends Person {
  private department: string;
  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return `Hello, my name is The ${this.name} and I work in The ${this.department}. `; }}let howard = new Jack("Jack"."Technical Department");
console.log(howard.getElevatorPitch());
console.log(Jack.name);
console.log(Person.name)
console.log(howard.name);//Property 'name' is protected and only accessible within class 'Person' and its subclasses. Only accessible in class "Person" and its subclasses.)
Copy the code

Protected When a constructor is marked, the class cannot be instantiated, but can be extended (inherited) as follows:

class Person {
  protected name: string;
  protected constructor(theName: string) {
    this.name = theName; }}// Can be inherited
class Jack extends Person {
  private department: string;
  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    return `Hello, my name is The ${this.name} and I work in The ${this.department}. `; }}let howard = new Jack("Jack"."Technical Department");
let john = new Person("John");//Constructor of class 'Person' is protected and only accessible within the class declaration. Can only be accessed in class declarations.
Copy the code

Read-only modifier

In Typescrip, we use the readonly keyword to make properties read-only. Read-only properties must be initialized in their declaration or constructor as follows:

class Person {
  readonly name: string;
  readonly numberOfLegs: number = 8;

  constructor(theName: string) {
    this.name = theName; }}let dad = new Person("jack");
console.log(dad.name);
dad.name = "jack";// Name is a read-only property and cannot be assigned
Copy the code

accessor

Getters /setters methods are supported in Typescript. By accessing members of intercepting objects, we have more control over how members are accessed on each object. This helps prevent abnormal data.

let nameMaxLength = 8;
class Person {
  private _name: string;
  constructor(newName:string){
    this._name = newName;
  }
  get name() :string {
    return this._name;
  };
  set name(newName: string) {
    if (newName && newName.length > nameMaxLength) {
      console.log('Names cannot be longer than '+ nameMaxLength);
      return;
    }
    this._name = newName; }}let Jack = new Person('Jack');
Jack.name = 'JackWangs';
if(Jack.name){
console.log(Jack.name);
}
Copy the code

An abstract class

An abstract class is a base class that can be derived from other classes. An abstract class cannot be instantiated. Unlike interfaces, abstract classes may contain implementation details for other members. Typically, we use the abstract keyword declaration to define abstract classes as follows:

abstract class Animal{
  name:string;
  constructor(newName:string){
    this.name = newName;
  }
  abstract move(distance:number) :void
}
let dog = new Animal();//error:Cannot create an instance of an abstract class
Copy the code

Since an abstract class cannot be instantiated directly, we can invoke properties and methods of the abstract class by instantiating a subclass of the abstract class as follows:

abstract class Animal{
  name:string;
  constructor(newName:string){
    this.name = newName;
  }
  abstract move(distance:number) :void
}
class Dogs extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distance: number) :void {
    console.log(`The ${this.name} moved ${distance}m`); }}let dog = new Dogs('dog');
dog.move(10);
Copy the code

Class method overloading

Class method overloading and function overloading work in much the same way, with the following code:

class Animal{
	getID():void;
    getID(id: number) :void;
    getID(id? :number){
        if(typeof id==="number") {console.log('gets the ID as${id}Of animal species);
        }else{
          console.log('Get all animal species'); }}}let dog = new Animal();
dog.getID(10);//" Get animal species with id 10"
dog.getID()//" Get all animal species"
Copy the code

Use classes as interfaces

A class declaration creates two things: a type that represents an instance of the class and a constructor. Since classes create types, they can be used where interfaces can be used, as follows:

class Person{
    name:string;
    age:number
}

interface Person2 extends Person{
  hobby:string
}
let jack:Person2={name:'jack'.age:19.hobby:'Play basketball'};

function person(msg:Person2){
  console.log(msg);
}
person(jack);//{"name": "jack","age": 19,"hobby": "basketball "}
Copy the code