我们可以像在 Java 里一样,声明一个 Greeter 类,然后使用 new 来构造一个 Greeter 类的实例:

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

let greeter = new Greeter("world");

继承

和 Java 中一样,类之间是可以继承的。

class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}

class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}

const dog = new Dog();
dog.bark();
dog.move(10);

在 TypeScript 中,若派生类包含了一个构造函数,它必须调用 super(),它会执行基类的构造函数。而且,在构造函数里访问 this的属性之前,一定要调用 super()

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

class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}

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

修饰符

在TypeScript里,成员都默认为 public。

private

当成员被标记成 private时,它就不能在声明它的类的外部访问。比如:

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

new Animal("Cat").name; // Error: 属性“name”为私有属性,只能在类“Animal”中访问。

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); // Error

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"; // Error: Cannot assign to 'name' because it is a read-only property.

参数属性

参数属性可以方便地让我们在一个地方定义并初始化一个成员。 参数属性通过给构造函数参数前面添加一个访问限定符来声明。public、private、protected、readonly 都可以。

// 调用构造器方法时候,会定义并初始化一个 readonly 的 name 属性
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {
}
}

存取器

TypeScript支持通过getters/setters来截取对对象成员的访问。但与 Java 不同的是,添加了 getters/setters 方法后,我们还是使用 . 来存取这个属性

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

静态属性

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

抽象类

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(); // Error: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // Error: 方法在声明的抽象类中不存在

Tips

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());

// typeof Greeter,意思是取Greeter类的类型,而不是实例的类型。
// greeterMaker 包含了 Greeter 类的所有静态成员和构造函数。
let greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = "Hey there!";

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