TS入门学习第四篇
类
TypeScript支持基于类的面向对象的编程方式,定义类的关键字为 class,后面紧跟类名。类描述了所创建的对象共同的属性和方法。
普通类
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
继承
在TypeScript里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
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.move(10);
dog.bark();
这个例子展示了最基本的继承:类从基类中继承了属性和方法。 这里,Dog是一个派生类,它派生自Animal基类,通过extends关键字。 派生类通常被称作子类,基类通常被称作超类。
因为Dog继承了Animal的功能,因此我们可以创建一个Dog的实例,它能够bark()和move()。
公共,私有与受保护的修饰符,readonly修饰符,静态属性
在TypeScript里,成员都默认为public。
当成员被标记成private时,它就不能在声明它的类的外部访问。
protected修饰符与private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问。
class Animal {
public namePub: string;
private namePri: string;
protected namePro: string;
constructor(theName: string) {
this.namePub= theName;
this.namePri= theName;
this.namePro= theName;
}
}
new Animal("Cat").namePub; //可以调用
new Animal("Cat").namePri; // 错误: 'name' 是私有的.
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
let rhino = new Rhino();
rhino.namePro;//可以调用
你可以使用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 Grid {
static origin = {x: 0, y: 0};
}
我们使用Grid.origin 来访问静态属性。
抽象类
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 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();
泛型
我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了类型变量,它是一种特殊的变量,只用于表示类型而不是值。
//不用泛型的话,这个函数可能是下面这样:
function identity(arg: number): number {
return arg;
}
//使用泛型
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <T>(arg: T) => T = identity;
这引导我们去写第一个泛型接口了。 我们把上面例子里的对象字面量拿出来做为一个接口:
interface GenericIdentityFn {
<T>(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
泛型类
泛型类看上去与泛型接口差不多。 泛型类使用(<>)括起泛型类型,跟在类名后面。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };