TypeScript独学---第四章:類


クラス#クラス#
次にクラスの使用を見てください
class Greeter {
  greeting: string;
  constructor(message: string) {
      this.greeting = message;
  }
  greet() {
      return "Hello, " + this.greeting;
  }
}

let greeter = new Greeter("world");

3つの部分の1つはgreetingという属性であり、1つの構造関数と1つのgreet方法である.
継承
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) //     move  
  }
}

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)

派生クラスには、ベースクラスのコンストラクション関数を実行するsuper()を呼び出すコンストラクション関数が含まれています.コンストラクタでthisプロパティにアクセスするには、super()を呼び出す必要があります.また、この例ではmoveメソッドも書き換えられています.
//    
Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.

パブリック、プライベート、保護された修飾子
public
TypeScriptでは、メンバーのデフォルトはpublicです.このように書くこともできます
class Animal {
  public name: string;
  public constructor(theName: string) { this.name = theName; }
  public move(distanceInMeters: number) {
      console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}

private
メンバーがprivateとマークされている場合、クラスを宣言する外部アクセスはできません.
class Animal {
  private name: string;
  constructor(theName: string) { this.name = theName; }
}   

new Animal("Cat").name; //   : 'name'     .

protected protected修飾子は、private修飾子の動作と似ていますが、protectedメンバーは派生クラスにアクセスできます.
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); //   

コンストラクタはprotectedとしてマークすることもできる.では、このクラスは継承できますが、インスタンス化できません.
class Person {
  protected name: string;
  protected constructor(theName: string) { this.name = theName; }
}

// Employee      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"); //   : 'Person'           .

readonly修飾子
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"; //   ! name     .

パラメータのプロパティ
前の段落をパラメータプロパティで変更します.次のようになります.
class Octopus {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string) {
  }
}

パラメータ属性は、コンストラクション関数パラメータの前にアクセス制限子を追加することによって宣言されます.privateを使用してパラメータ属性を定義すると、プライベートメンバーが宣言され、初期化されます.publicおよびprotectedについても同様である.
アクセス装置
アクセサのないコード
class Employee {
  fullName: string;
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
  console.log(employee.fullName);
}
setメソッドとgetメソッド
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);
}

注意getのみを有し、setを有しないアクセサは、readonlyと自動的に推定される.
静的プロパティ
静的プロパティはクラスにのみ存在し、クラスのインスタンスには存在しません.
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 }));
staticを使用してoriginを定義します.これは、すべてのグリッドで使用されるプロパティです.各インスタンスがこのプロパティにアクセスするには、originの前にクラス名を付けます.すなわち、Grid.は、静的属性にアクセスする.
抽象クラス
抽象クラスは、他の派生クラスのベースクラスとして使用されます.一般的には、インスタンス化されません.
abstract class Animal {
  abstract makeSound(): void;
  move(): void {
    console.log("roaming the earch...");
  }
}

抽象クラスの抽象メソッドには、特定の実装は含まれず、派生クラスで実装する必要があります.抽象メソッドの構文はインタフェースメソッドと似ています.どちらもメソッド署名を定義しますが、メソッドボディは含まれません.しかしながら、抽象的な方法は、abstractキーワードを含み、アクセス修飾子を含むことができる.
abstract class Department {
  constructor(public name: string) {}

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

  abstract printMeeting(): void; //          
}

class AccountingDepartment extends Department {
  constructor() {
    super("Accounting and Auditing"); //                super()
  }

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

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

let department: Department; //               
department = new Department(); //   :             
department = new AccountingDepartment(); //                  
department.printName();
department.printMeeting();
department.generateReports(); //   :              

高度なテクニック
コンストラクタ
// ts  
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());
//        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());

クラスにはインスタンス部分と静的部分の2つの部分があると考えられる.この例を少し書き直して、違いを見てみましょう.
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());

クラスをインタフェースとして使用する
class Point {
  x: number;
  y: number;
}

interface Point3d extends Point {
  z: number;
}

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