TypeScript self study - Chapter 4: classes

class

Let's see the use of classes

class Greeter {
  greeting: string;
  constructor(message: string) {
      this.greeting = message;
  }
  greet() {
      return "Hello, " + this.greeting;
  }
}

let greeter = new Greeter("world");

There are three parts: a property called greeting, a constructor, and a greet method.

inherit

class Animal {
   name:string
   constructor(theName:string){
     this.name = theName
   }
   move(distanceInMeters:number = 0){
     console.log(`${this.name} moved ${distanceInMeters}.`)
   }
}

class Snake extends Animal {
  constructor(name:string){
    super(name)
  }
  move(distanceInMeters = 5){
    console.log("Slithering...")
    super.move(distanceInMeters) //Call the move method of the parent class
  }
}

class Horse extends Animal {
  constructor(name:string){
    super(name)
  }
  move(distanceInMeters = 45){
    console.log("Galloping...")
    super.move(distanceInMeters)
  }
}

let sam = New Snake("Sammy the Python")
let tom:Animal = new Horse("Tommy the Palomino")
sam.move()
tom.move(34)

A derived class contains a constructor that must call super(), which executes the constructor of the base class.
If you want to access this property in the constructor, you must first call super()
At the same time, this example rewrites the move method

//Print results
Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.

Public, private and protected modifiers

public

In TypeScript, members default to public.
You can write it like this

class Animal {
  public name: string;
  public constructor(theName: string) { this.name = theName; }
  public move(distanceInMeters: number) {
      console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}
private

When a member is marked private, it cannot be accessed outside the class that declares it

class Animal {
  private name: string;
  constructor(theName: string) { this.name = theName; }
}   

new Animal("Cat").name; // Error: 'name' is private
protected

The protected modifier behaves much like the private modifier, but the protected member is still accessible in the derived class.

class Person {
  protected name: string;
  constructor(name: string) { this.name = name; }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
      super(name)
      this.department = department;
  }

  public getElevatorPitch() {
      return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}

let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error

The constructor can also be marked protected. Then this class can be inherited, but cannot be instantiated.

class Person {
  protected name: string;
  protected constructor(theName: string) { this.name = theName; }
}

// Employee can inherit Person
class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
      super(name);
      this.department = department;
  }

  public getElevatorPitch() {
      return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}

let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: the constructor for 'Person' is protected

readonly modifier

class Octopus {
  readonly name: string;
  readonly numberOfLegs: number = 8;
  constructor (theName: string) {
      this.name = theName;
  }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // Error! name is read-only

Parameter properties

Use parameter attributes to modify the previous paragraph. As follows:

class Octopus {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string) {
  }
}

Parameter properties are declared by adding an access qualifier to the front of the constructor parameter. Using private to qualify a parameter property declares and initializes a private member; the same is true for public and protected.

Accessor

Code without accessor

class Employee {
  fullName: string;
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
  console.log(employee.fullName);
}

set method and get method

let passcode = "secret passcode";

class Employee {
  private _fullName: string;

  get fullName(): string {
    return this._fullName;
  }

  set fullName(newName: string) {
    if (passcode && passcode == "secret passcode") {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
  alert(employee.fullName);
}

Note that accessors with only get and no set are automatically inferred as readonly.

Static properties

Static properties exist only on the class, not on the instance of the class.

class Grid {
  static origin = { x: 0, y: 0 };
  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;
  }
  constructor(public scale: number) {}
}

let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale

console.log(grid1.calculateDistanceFromOrigin({ x: 10, y: 10 }));
console.log(grid2.calculateDistanceFromOrigin({ x: 10, y: 10 }));

Use static to define origin, because it is an attribute used by all grids. When each instance wants to access this property, it needs to add the class name before the origin. Grid. To access static properties.

abstract class

Abstract classes are used as base classes of other derived classes. They are generally not instantiated directly.

abstract class Animal {
  abstract makeSound(): void;
  move(): void {
    console.log("roaming the earch...");
  }
}

Abstract methods in abstract classes do not contain concrete implementations and must be implemented in derived classes. The syntax of an abstract method is similar to that of an interface method. Both define method signature but do not include method body. However, an abstract method must contain the abstract keyword and can contain access modifiers.

abstract class Department {
  constructor(public name: string) {}

  printName(): void {
    console.log("Department name: " + this.name);
  }

  abstract printMeeting(): void; // Must be implemented in a derived class
}

class AccountingDepartment extends Department {
  constructor() {
    super("Accounting and Auditing"); // super() must be called in the constructor of a derived class
  }

  printMeeting(): void {
    console.log("The Accounting Department meets each Monday at 10am.");
  }

  generateReports(): void {
    console.log("Generating accounting reports...");
  }
}

let department: Department; // Allow to create a reference to an abstract type
department = new Department(); // Error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // Allow instantiation and assignment of an abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // Error: method does not exist in the declared abstract class

Advanced skills

Constructor
// ts writing
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return 'Hello, ' + this.greeting;
  }
}
let greeter: Greeter;
greeter = new Greeter('world');
console.log(greeter.greet());
// Previous paragraph changed to JS
let Greeter = (function() {
  function Greeter(message) {
    this.greeting = message;
  }
  Greeter.prototype.greet = function() {
    return 'Hello, ' + this.greeting;
  };
  return Greeter;
})();

let greeter;
greeter = new Greeter('world');
console.log(greeter.greet());

We can think of a class as having two parts: the instance part and the static part.
Let's rewrite this example a little to see the difference between them:

class Greeter {
  static standardGreeting = 'Hello, there';
  greeting: string;
  greet() {
    if (this.greeting) {
      return 'Hello, ' + this.greeting;
    } else {
      return Greeter.standardGreeting;
    }
  }
}

let greeter1: Greeter;
greeter1 = new Greeter();
console.log(greeter1.greet());

let greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = 'Hey there!';

let greeter2: Greeter = new greeterMaker();
console.log(greeter2.greet());

Using classes as interfaces

class Point {
  x: number;
  y: number;
}

interface Point3d extends Point {
  z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

Keywords: Javascript Python TypeScript Attribute

Added by ronald29x on Thu, 25 Jun 2020 15:20:30 +0300