基本使用
class Greeter {
// 属性
greeting: string;
// 构造函数
constructor(message: string) {
// 用this 访问类的属性
this.greeting = message;
}
// 方法
greet() {
return 'Hello, ' + this.greeting;
}
}
// 实例化
let greeter = new Greeter('World');
声明了一个Greeter
类,类有三个成员:一个是 greeting
属性,一个构造函数和一个greet
方法。使用new
关键字实例化Greeter
对象。实例化时会调用类的构造函数,并返回一个对象。
继承
使用
extends
关键字。
派生类(子类) 包含构造函数就必须调用super()
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
最基本的继承:类从基类中继承了属性和方法。
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方法
move(distanceInMeters = 5) {
console.log('Slithering....');
super.move(distanceInMeters);
}
}
class Horse extends Animal {
constructor(name: string) {
super(name);
}
// 重写父类move方法
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);
公有、私有与受保护的修饰符
在类中所有成员都默认被公有
public
修饰符修饰。
public
公有- 公有(
public
)成员可能在类的外部访问
- 公有(
class Animal {
public name: string;
public constructor(theName: string) {
this.name = theName;
}
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}`);
}
}
let animal = new Animal('dog');
animal.name = 'Cat';
animal.move(20);
private
私有- 当成员被标记成
private
时,属性或方法就不能在类的外部访问 - 子类不能访问父类的
private
修饰的属性 constructor
可以被private
修饰,但是这样类就不能被实例化,也不能被子类继承
- 当成员被标记成
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
class Dog extends Animal {
constructor(theName: string) {
super(theName);
}
move() {
console.log(`${this.name}`); // 报错,子类不能访问父类的私有属性
}
}
let animal = new Animal('dog');
animal.name = 'cat'; // 报错,name 是私有属性,类外不能访问
- 如果两个的类型的所有成员的类型都是兼容的,那么这两类型是兼容的。但是这两个类型的其中一个类型包含
private
成员,那么只有当另一个类型中也存在这样一个private
成员,并且来自同一处声明时,才能认为这两个类型是兼容的protected
成员也使用这个规则
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
class Rhino extends Animal {
constructor() {
super('Rhino');
}
}
class Employee {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
let animal = new Animal('Goat');
let rhino = new Rhino();
let employee = new Employee('Bob');
animal = rhino;
animal = employee; // 错误:Animal 与 Employee 不兼容
protected
保护- 子类可以访问父类的
protected
修饰的成员。但是protected
修饰的成员不能再类的外部访问 constructor
可以被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 修饰的属性不能再类的外部访问
readonly
修饰符
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是只读的
参数属性
参数属性通过给构造函数参数前面添加一个访问限定符来声明。
会同时声明并初始化一个成员
- 使用
readonly
修饰的属性与构造函数的参数结合。
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {}
}
let dad = new Octopus('Man with the 8 strong legs');
dad.name = 'Man with the 3-piece suit'; // 错误 namename 只读
console.log(dad.name);
- 使用
public
修饰的属性与构造函数的参数结合。
class Octopus {
readonly numberOfLegs: number = 8;
constructor(public name: string) {}
}
let dad = new Octopus('man');
console.log(dad.name);
- 使用
private
修饰的属性与构造函数的参数结合。
class Octopus {
readonly numberOfLegs: number = 8;
constructor(private name: string) {}
getName() {
return this.name;
}
}
let dad = new Octopus('man');
console.log(dad.getName());
- 使用
protected
修饰的属性与构造函数的参数结合。
class Octopus {
readonly numberOfLegs: number = 8;
constructor(protected name: string) {}
getName() {
return this.name;
}
}
let dad = new Octopus('man');
console.log(dad.getName());
存储器
typescript 支持通过 getters/setters 来截取对对象成员的访问。
只有get
没有set
的会自动被推断为readonly
。
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);
}
静态属性
关键字:
static
静态属性是存在于类本身,不存在与类的实例。
同一个类的实例对象共享类上的静态属性的状态。
通过类名.
方式访问静态属性
class Grid {
static origin = {x: 0, y: 0};
constructor(public scale: number) {}
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;
}
}
let grid1 = new Grid(1.0);
let grid2 = new Grid(5.0);
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
抽象类
关键字:
abstract
抽象类不能直接被实例化,只能通过派生类(子类)继承,实例化派生类(子类)。
抽象类类似于接口,但是抽象类可以包含成员的实现细节。
抽象类的抽象方法不包含具体实现并且必须在派生类(子类)中实现。
抽象方法必须在方法前声明abstract
关键字并且可以包含访问修饰符
abstract class Deparment {
constructor(public name: string) {}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Deparment {
constructor() {
super('Accounting and Auditing'); // 在派生类的构造函数必须调用
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
let department: Deparment; // 允许创建一个抽象类型的引用
// department = new Deparment(); // 错误 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许创建一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports(); // 错误:方法在声明的抽象类中不存在
构造函数
- 类的实例化会调用类的构造函数
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());
特别注意:创建一个
greeterMaker
的变量,这个变量保存了这个类或者说保存了类构造函数。然后用typeof greeter
,意思是取Greeter
类的类型,而不是实例的类型,也就是构造函数的类型。这个类型包含了类的所有静态成员和构造函数。
类当作接口使用
类定义会创建类的实例类型和一个构造函数
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};