Skip to content
创建时间: 2020年10月6日

接口

  • 接口一方面可以在面向对象编程中表示为行为的抽象,另外可以用来描述对象的形状
  • 接口就是把一些类中共有的属性和方法抽象出来,可以用来约束实现此接口的类
  • 一个类可以继承另一个类并实现多个接口
  • 接口像插件一样是用来增强类的,而抽象类是具体类的抽象概念
  • 一个类可以实现多个接口,一个接口也可以被多个类实现,但一个类的可以有多个子类,但只能有一个父类

1. 接口

  • interface中可以用分号或者逗号分割每一项,也可以什么都不加

1.1 对象的形状

ts
//接口可以用来描述`对象的形状`,少属性或者多属性都会报错
interface Speakable {
  speak(): void;
  name?: string; //?表示可选属性
}

let speakman: Speakable = {
  speak() {}, //少属性会报错
  name,
  age, //多属性也会报错
};

1.2 行为的抽象

ts
//接口可以在面向对象编程中表示为行为的抽象
interface Speakable {
  speak(): void;
}
interface Eatable {
  eat(): void;
}
//一个类可以实现多个接口
class Person implements Speakable, Eatable {
  speak() {
    console.log("Person说话");
  }
  eat() {}
}
class TangDuck implements Speakable {
  speak() {
    console.log("TangDuck说话");
  }
  eat() {}
}

1.3 任意属性

ts
//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
interface Person {
  readonly id: number;
  name: string;
  [propName: string]: any;
}

let p1 = {
  id: 1,
  name: "hello ",
  age: 10,
};

2. 接口的继承

  • 一个接口可以继承自另外一个接口
ts
interface Speakable {
  speak(): void;
}
interface SpeakChinese extends Speakable {
  speakChinese(): void;
}
class Person implements SpeakChinese {
  speak() {
    console.log("Person");
  }
  speakChinese() {
    console.log("speakChinese");
  }
}

3. readonly

  • 用 readonly 定义只读属性可以避免由于多人协作或者项目较为复杂等因素造成对象的值被重写
ts
interface Person {
  readonly id: number;
  name: string;
}
let tom: Person = {
  id: 1,
  name: "hello ",
};
tom.id = 1;

4. 函数类型接口

  • 对方法传入的参数和返回值进行约束
ts
interface discount {
  (price: number): number;
}
let cost: discount = function (price: number): number {
  return price * 0.8;
};

5. 可索引接口

  • 对数组和对象进行约束
  • userInterface 表示index的类型是 number,那么值的类型必须是 string
  • UserInterface2 表示:index 的类型是 string,那么值的类型必须是 string
ts
interface UserInterface {
  [index: number]: string;
}
let arr: UserInterface = ["hahaha 1", "hahaha 2"];
console.log(arr);

interface UserInterface2 {
  [index: string]: string;
}
let obj: UserInterface2 = { name: "hello " };

6. 类接口

  • 对类的约束
ts
interface Speakable {
  name: string;
  speak(words: string): void;
}
class Dog implements Speakable {
  name!: string;
  speak(words: string) {
    console.log(words);
  }
}
let dog = new Dog();
dog.speak("汪汪汪");

7. 构造函数的类型

  • 在 TypeScript 中,我们可以用 interface 来描述类
  • 同时也可以使用interface里特殊的new()关键字来描述类的构造函数类型
ts
class Animal {
  constructor(public name: string) {}
}
//不加new是修饰函数的,加new是修饰类的
interface WithNameClass {
  new (name: string): Animal;
}
function createAnimal(clazz: WithNameClass, name: string) {
  return new clazz(name);
}
let a = createAnimal(Animal, "hello ");
console.log(a.name);

8. 抽象类 vs 接口

  • 不同类之间公有的属性或方法,可以抽象成一个接口(Interfaces)
  • 而抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
  • 抽象类本质是一个无法被实例化的类,其中能够实现方法和初始化属性,而接口仅能够用于描述,既不提供方法的实现,也不为属性进行初始化
  • 一个类可以继承一个类或抽象类,但可以实现(implements)多个接口
  • 抽象类也可以实现接口
ts
abstract class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  abstract speak(): void;
}
interface Flying {
  fly(): void;
}
class Duck extends Animal implements Flying {
  speak() {
    console.log("汪汪汪");
  }
  fly() {
    console.log("我会飞");
  }
}
let duck = new Duck("hello ");
duck.speak();
duck.fly();