下面请看类的使用

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

有三个部分一个叫做 greeting的属性,一个构造函数和一个 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 能够继承 Personclass 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限定一个参数属性会声明并初始化一个私有成员;对于 publicprotected来说也是一样。

存取器

无存取器的代码

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 scalelet grid2 = new Grid(5.0); // 5x scaleconsole.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());

我们可以认为类具有实例部分静态部分这两个部分。
让我们稍微改写一下这个例子,看看它们之间的区别:

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};