TypeScript 接口
类型注解中接口的使用
- 可以把接口当作描述类型的工具使用,有点类似
type
关键字的感觉。 - 接口支持和
type
的交叉类型。
// 定义
interface afObj { // 这样写描述了一个对象结构
name: string;
age: number;
}
interface AddFunction { // 这样写描述了一个函数类型
(a: number, b: number): number;
}
// 使用
const obj: afObj = {
name: 'xx',
age: 13,
};
const add: AddFunction = (x, y) => {
return x + y;
};
接口的继承
interface Parent {
prop1: string;
prop2: number;
}
// 继承
interface Child extends Parent {
prop3: string;
}
const myObj: Child = {
prop1: '',
prop2: 2,
prop3: '',
};
接口声明合并
同样的接口声明不会覆盖,而是合并
interface Parent {
prop1: string;
prop2: number;
}
// 继承
interface Parent {
prop3: string;
}
const myObj: Parent = {
prop1: '',
prop2: 2,
prop3: '',
};
抽象类与接口
抽象类和接口相似,都是一种比较特殊的类,抽象类是一种特殊的类,而接口也是一种特殊的抽象类,他们通常配合面向对象的多态性一起使用,虽然声明和使用都比较容易,但他们的作用在理解上会困难一点。
抽象类
在 OOP 语言中一个类可以有一个或多个子类,而每个类都有至少一个公有方法作为外部代码访问他的接口。而抽象方法就是为了方便继承而引入的。
抽象方法就是没有方法体的方法,所谓没有方法体是指在方法声明时没有花括号及其中的内容,而是在声明方法时直接在方法名后加上分号结束。另外,声明抽象方法时,还要使用关键字 abstract
来修饰声明。
只要在声明类时,有一个方法是抽象方法,那么这个类就是抽象类,抽象类也要使用关键字 abstract
来修饰。在抽象类中,可以有不是抽象的成员方法和成员属性,但访问权限不能使用 private
关键字修饰为私有的。
abstract class Animal {
abstract name: string; // 抽象属性
abstract fun1(): string; // 抽象方法
fun2(): void {
// 普通方法。不能使用 private 关键字修饰为私有的。
console.log('fun2');
}
}
class Cat extends Animal {
name: string = 'xjj';
fun1(): string {
return 'Good';
}
}
抽象类有什么作用呢?使用抽象类就包含了继承关系,它是为它的子类定义公共接口,将它的操作交给子类去实现。就是将抽象类作为子类重载的模板使用,定义抽象类就相当于定义的一种规范,这种规范要求子类去遵守。当子内继承抽象类以后,就必须把抽象类中的抽象方法按照子类自己的需求去实现。子类必须把父内中的抽象方法全部实现,否则子类还存在抽象方法,所以还是抽象类,也不能实例化对象。
接口技术
因为 TypeScrtip 只支持单继承,也就是说每个类只能继承一个父类。当声明的新类继承抽象类实现模板以后,它就不能再有其他父类了。为了解决这个问题,TypeScrtip 引入了接口。接口是一种特殊的抽象类,而抽象类又是一种特殊的类,所以接口也是一种特殊的类。如果抽象类中的所有方法都是抽象方法,那么我们就可以换另外一种声明方式————使用「接口」技术。
接口中声明的方法必须都是抽象方法,而且接口中的所有成员都必须有 public
的访问权限。类的声明是使用「class」关键字标识的,而接口的声明则是使用「interface」关键字标识的。
接口中所有的方法都要求是抽象方法,所以就不需要在方法前使用 abstract
关键字标识了。而且在接口中也不需要显式地使用 public
访问权限进行修饰,因为默认权限就是 public
的,也只能是 public
的。另外,接口和抽象类一样也不能实例化对象,它是一种更严格的规范,也需要通过子类来实现。
如果需要使用接口中的成员,则需要通过子类去实现接口中的全部抽象方法,然后创建子类的对象去调用在子类中实现后的方法。但通过类去继承接口时需要使用 implements
关键字来实现,而并不是使用 extends
关键字完成。如果需要使用抽象类去实现接口中的部分方法,也需要使用 implements
关键字实现。
// 定义接口
interface Animal {
name: string;
fun1(): void;
fun2(): void;
}
// 使用接口
class Cat implements Animal {
// 实现接口中的成员属性
name: string = 'mimi';
// 实现接口中的方法
fun1(): void {
console.log(this.name);
}
// 抽象方法
fun2(): string {
return 'miaomiao';
}
}
// 接口变抽象类
abstract class Mammal implements Animal {
// 实现接口中的成员属性
name: string = 'wangwang';
// 实现接口中的方法
fun1(): void {
console.log(this.name);
}
// 抽象方法
abstract fun2(): string;
}
// 使用抽象类
class Dog extends Mammal {
fun2(): string {
return 'Woof!';
}
}
// 继承的同时实现接口
class Fish extends Mammal implements Animal {
fun2(): string {
return 'Bubble';
}
}
接口的使用案例
interface PayInterface {
handle(price: number): void;
}
class AliPay implements PayInterface {
handle(price: number) {
console.log(`支付宝付款${price}元`);
}
}
class WePay implements PayInterface {
handle(price: number) {
console.log(`微信付款${price}元`);
}
}
function pay(type: string, price: number): void {
let payObj: PayInterface;
switch (type) {
case 'alipay':
payObj = new AliPay();
break;
case 'wepay':
payObj = new WePay();
break;
default:
throw new Error('不支持的支付方式');
}
payObj.handle(price);
}