本篇将介绍TypeScript里的类和接口。

与其他强类型语言类似,TypeScript遵循ECMAScript 2015标准,支持class类型,同时也增加支持interface类型。

一、类(class)

下面是一个类的基本定义方式:

 class User {
name: string;
constructor(_name: string) {
this.name = _name;
} sayHello(): string {
return `Hello,${this.name}!`;
}
} let user = new User('John Reese');
user.sayHello();

在上面的例子里,定义了一个类User,这个类拥有一个属性、一个构造函数和一个实例方法sayHello。通过new的方式,可以用这个类实例化一个实例对象,并可以调用实例方法。这与大多数静态语言的声明方式一致。

1. 类成员的访问级别

与强类型语言类似,TypeScript的类成员可以显式声明访问级别:public、protected、private

 class User {
name: string;
private sex: string;
protected age: number;
constructor(_name: string) {
this.name = _name;
} sayHello(): string {
return `Hello,${this.name}!`;
}
} let user = new User('John Reese');
user.name = 'Root'; // 公有属性,可以赋值
user.sex = 'female'; // 私有属性,无法赋值
user.age = 28; // 受保护属性,无法赋值
user.sayHello();

在TypeScript里,如果不显示指定访问级别,则默认为public。

2. 属性的get和set访问器

 class User {
private _name: string; get name(): string {
return this._name;
} set name(newName: string) {
this._name = newName;
} constructor(_name: string) {
this.name = _name;
} sayHello(): string {
return `Hello,${this._name}!`;
}
} let user = new User('John Reese');
user.name = 'Root';
user.sayHello();

通过get和set关键字声明属性访问器,通过属性访问器可以精确控制属性的赋值和获取值。下面是经过编译后生成的JavaScript代码

 var User = (function () {
function User(_name) {
this.name = _name;
}
Object.defineProperty(User.prototype, "name", {
get: function () {
return this._name;
},
set: function (newName) {
this._name = newName;
},
enumerable: true,
configurable: true
});
User.prototype.sayHello = function () {
return "Hello," + this._name + "! " + this._age;
};
return User;
}());
var user = new User('John Reese');
user.name = 'Root';
user.sayHello();

3. 静态属性

静态属性即是通过类型而不是实例就可以访问的属性

 class User {
static sex_type = ['male', 'female']; // 静态属性
name: string;
sex: string; constructor(_name: string) {
this.name = _name;
} sayHello(): string {
return `Hello,${this.name}!`;
}
} let user = new User('John Reese');
user.name = 'Root';
user.sex = User.sex_type[1];
user.sayHello();

通过static关键字可以声明类型的静态属性。

4. 类的继承

同强类型语言一样,TypeScript也支持类的继承

 // 基类
class Animal {
name: string; constructor(theName: string) {
this.name = theName;
} eat() {
console.log(`${this.name} 吃食物。`);
}
} // 子类继承基类
class Dog extends Animal {
constructor(theName: string) {
super(theName);
} eat() {
super.eat();
console.log('并且吃的是狗粮。');
}
} class People extends Animal {
constructor(theName: string) {
super(theName);
} // 子类重写基类方法
eat() {
console.log(`${this.name} 拒绝吃狗粮。`);
}
} let animal = new Animal('动物');
animal.eat(); let dog: Animal;
dog = new Dog('狗');
dog.eat(); let people: Animal;
people = new People('人类');
people.eat();

从上面的例子可以看到,子类通过extends关键字可以继承其他类,通过super方法调用基类对应的方法,也可以直接重写基类的方法。

下面是编译之后生成JavaScript源码,可以比较看看

 var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
// 基类
var Animal = (function () {
function Animal(theName) {
this.name = theName;
}
Animal.prototype.eat = function () {
console.log(this.name + " \u5403\u98DF\u7269\u3002");
};
return Animal;
}());
// 子类继承基类
var Dog = (function (_super) {
__extends(Dog, _super);
function Dog(theName) {
_super.call(this, theName);
}
Dog.prototype.eat = function () {
_super.prototype.eat.call(this);
console.log('并且吃的是狗粮。');
};
return Dog;
}(Animal));
var People = (function (_super) {
__extends(People, _super);
function People(theName) {
_super.call(this, theName);
}
// 子类重写基类方法
People.prototype.eat = function () {
console.log(this.name + " \u62D2\u7EDD\u5403\u72D7\u7CAE\u3002");
};
return People;
}(Animal));
var animal = new Animal('动物');
animal.eat();
var dog;
dog = new Dog('狗');
dog.eat();
var people;
people = new People('人类');
people.eat();

编译之后的JavaScript源码

5. 抽象类

将上面的例子稍微修改下

 // 抽象类
abstract class Animal {
name: string; constructor(theName: string) {
this.name = theName;
} abstract eat();
} // 子类继承抽象类
class Dog extends Animal {
constructor(theName: string) {
super(theName);
} eat() {
console.log(`${this.name} 吃狗粮。`);
}
} let animal = new Animal('动物'); // 抽象类无法实例化
animal.eat(); let dog: Animal;
dog = new Dog('狗');
dog.eat();

通过abstract关键字声明抽象类和抽象方法,子类继承抽象类后,需要实现抽象方法。同样的,抽象类不能被实例化。

二、接口

下面是一个简单的接口声明

 interface Animal {
name: string;
}

在JavaScript里没有对应的类型与之对应,所以编译之后不会生成任何JavaScript代码。

1. 作为参数类型

接口类型可以作为方法的参数类型,效果等同于直接指定Json对象的类型。

 interface Animal {
name: string;
} let printName = function(param: Animal) {
console.log(`Name is ${param.name}`);
} printName({name: 'Dog'});

同样,接口成员也可以是缺省的

 interface Animal {
name: string;
age?: number;
} let printName = function (param: Animal) {
if (param.age) {
console.log(`Name is ${param.name}, and age is ${param.age}`);
} else {
console.log(`Name is ${param.name}`);
}
} printName({ name: 'Dog' });
printName({ name: 'Dog', age: 5 });

但是在某些情况下,调用方法时,参数赋值可能会有多个,接口在作为参数类型时也支持拥有多个成员的情况。

 interface Animal {
name: string;
age?: number;
[propName: string]: any; // 其他成员
} let printName = function (param: Animal) {
if (param.age) {
console.log(`Name is ${param.name}, and age is ${param.age}`);
} else {
console.log(`Name is ${param.name}`);
}
} printName({ name: 'Dog' });
printName({ name: 'Dog', age: 5 });
printName({ name: 'Dog', age: 5, character: '粘人' }); // 多于明确定义的属性个数

2. 作为其他类型

接口也可以定义方法的类型,和数组类型

 interface FuncType {
(x: string, y: string): string; // 声明方法成员
} let func1: FuncType;
func1 = function (prop1: string, prop2: string): string { // 方法参数名称不需要与接口成员的参数名称保持一致
return prop1 + ' ' + prop2;
} interface ArrayType {
[index: number]: string; // 声明数组成员
} let arr: ArrayType;
arr = ['Dog', 'Cat'];

3. 接口的继承与实现

同强类型语言一样,TypeScript的接口支持继承与实现。

 interface Animal {
name: string;
eat(): void;
} class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
} eat() {
console.log(`${this.name} 吃狗粮。`)
}
} class Cat implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
} eat() {
console.log(`${this.name} 吃猫粮。`)
}
} let dog: Animal;
dog = new Dog('狗狗');
dog.eat(); let cat: Animal;
cat = new Cat('喵星人');
cat.eat();

类通过implements关键字继承接口,并实现接口成员。

同时,接口也可以多重继承。

 interface Animal {
name: string;
eat(): void;
} interface Person extends Animal { // 继承自Animal接口
use(): void;
} class People implements Person {
name: string;
constructor(theName: string) {
this.name = theName;
} eat() {
console.log(`${this.name} 拒绝吃狗粮。`)
} use() {
console.log(`${this.name} 会使用工具。`)
}
} let man: Person;
man = new People('男人');
man.eat();
man.use();

4. 类型转换

在TypeScript里,接口可以对符合任一成员类型的对象进行转换,转换之后的对象自动继承了接口的其他成员。

 interface Animal {
name: string;
age: number;
eat(): void;
} let thing = { name: '桌子' };
let otherThing = <Animal>thing; // 类型转换
otherThing.age = 5;
otherThing.eat = function () {
console.log(`${this.name} 不知道吃什么。`)
};

上面的例子里,声明了拥有name属性的json对象,通过<>将json对象转换成了Animal类型的对象。转换后的对象则拥有了另外的age属性和eat方法。

5. 接口继承类

在TypeScript里,接口可以继承类,这样接口就具有了类里的所有成员,同时这个接口只能引用这个类或者它的子类的实例。

 class People {
name: string;
private age: number;
constructor(theName: string) {
this.name = theName;
} eat() {
console.log(`${this.name} 拒绝吃狗粮。`);
} use() {
console.log(`${this.name} 会使用工具。`)
}
} interface Animal extends People { // 接口 } class Man extends People { // 子类 } class Cat { // 拥有同样结构的另外一个类
name: string;
private age: number;
constructor(theName: string) {
this.name = theName;
} eat() {
// 具体实现
} use() {
// 具体实现
}
} let cat: Animal;
cat = new Cat('喵星人'); // Cat类不是People的子类,无法被Animal引用 let man: Animal;
man = new Man('男人');
man.eat();

当继承链过深,代码需要在某一个子类的类型下执行时,这种方法比较有效。

TypeScript学习笔记(四) - 类和接口的更多相关文章

  1. Typescript 学习笔记四:回忆ES5 中的类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  2. typescript学习笔记(三)---接口

    关于第二章的学习笔记是变量声明. 接口:TypeScript的核心原则之一是对值所具有的结构进行类型检查. 它有时被称做“鸭式辨型法”或“结构性子类型化”. 在TypeScript里,接口的作用就是为 ...

  3. 初探swift语言的学习笔记四(类对象,函数)

    作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29606137 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  4. [Scala]Scala学习笔记四 类

    1. 简单类与无参方法 class Person { var age = 0 // 必须初始化字段 def getAge() = age // 方法默认为公有的 } 备注 在Scala中,类并不声明为 ...

  5. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  6. Typescript 学习笔记五:类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  7. Typescript 学习笔记七:泛型

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  8. Typescript 学习笔记二:数据类型

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  9. Typescript 学习笔记三:函数

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  10. Typescript 学习笔记一:介绍、安装、编译

    前言 整理了一下 Typescript 的学习笔记,方便后期遗忘某个知识点的时候,快速回忆. 为了避免凌乱,用 gitbook 结合 marketdown 整理的. github地址是:ts-gitb ...

随机推荐

  1. vue+element 切换正式和测试环境

    1.package.json { "name": "element-starter", "description": "A Vue ...

  2. 深入理解FIFO

    深入理解FIFO(包含有FIFO深度的解释) FIFO: 一.先入先出队列(First Input First Output,FIFO)这是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行 ...

  3. ip地址、子网掩码、DNS的关系与区别

    首先ip地址可能表示内网或者外网地址: 内网也就是局域网,最直观的就是像网吧,公司内部的电脑用交换机,HUB,路由连起来的.再通过光钎.猫接入INTERNET的. 外网就像你家里的一台电脑.用猫拨号上 ...

  4. ConcurrentHashMap 产生NullPointerException

    今天测试在发给我一段报错日志后,根据日志定位到从ConcurrentHashMap 的缓存中get的时候,ConcurrentHashMap的底层抛出了空指针,当时感觉很奇怪为什么在get的时候产生空 ...

  5. 学号20155308 2016-2017-2 《Java程序设计》第5周学习总结

    学号20155308 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 8.1 语法与继承架构 使用try...catch 注意多个catch一定把父类放后面 ...

  6. 61.volatile关键字

    volatile作用 volatile的作用是可以保持共享变量的可见性,即一个线程修改一个共享变量后,另一个线程能够读取到这个修改后的值. 先来看一个问题: 定义一个Task类 package com ...

  7. 【译】第八篇 SQL Server代理使用外部程序

    本篇文章是SQL Server代理系列的第八篇,详细内容请参考原文 在这一系列的上一篇,学习了如何用SQL Server代理作业活动监视器监控作业活动和查看作业历史记录.在实时监控和管理SQL Ser ...

  8. JS设计模式——9.组合模式

    组合模式概述 组合模式是一种专为创建Web上的动态用户界面量身定制的模式.使用这种模式可以用一条命令在多个对象上激发复杂的递归的行为. 它可以用来把一批子对象组织成树形结构,并且使整棵树都可被遍历.所 ...

  9. 字符串hash&&对字符串hash的理解

     对字符串hash的一些总结: 1,首先,我们在转化的时候,取底的时候一般是取131这些数,因为要避免不同的字符串对应相同的hash值这种情况的出现.如果卡精度的时候,我们可以采取双模数的方式尽量减少 ...

  10. 用Qemu模拟vexpress-a9 (一) --- 搭建Linux kernel调试环境【转】

    转自:http://www.cnblogs.com/pengdonglin137/p/5023342.html#_label2 阅读目录(Content) 环境介绍: 下载Linux内核 安装arm的 ...