接口

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-05-21

interface 经常被用来定一个不包含数据和逻辑代码但用函数简名定义了行为的抽象类型;

在传统的面向对象概念中,一个类可以扩展另一个类,也可以实现一个或多个接口。一个接口可以实现一个或多个接口但是不能扩展另一个类或接口;

TypeScript中,接口有两点不同于其他常规OOP语言意义上的接口

  • 接口可以扩展其他接口或者类;
  • 接口可以定义数据和行为;

接口:可索引的类型

interface StringArray {
  [index: number]: string;  // 以数字作为索引 value为string
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];


interface NumberDictionary {
  [index: string]: number;
  length: number;    // 可以,length是number类型
  name: string       // 错误,“name”不能赋给字符串索引类型“number”
}

// 之后定义的属性索引  应该与字符串索引类型保持一致 即index声明的那一行
// 因为所有的属性 key  都是字符串类型  首先就会满足第一行的 然后验证值是不是 number

接口:数字索引对应的类型必须是字符串索引返回值的子类型

class Animal {
  name: string;
  constructor(name:string) {
    this.name = name;
  }
}
class Dog extends Animal {
  breed: string;
  constructor(name:string, breed:string) {
    super(name);
    this.breed = breed;
  }
}

// 错误
interface NotOkay {
  [x: number]: Animal;
  [x: string]: Dog;
}

// 正确:
interface Okay {
  [x: string]: Animal;
  [x: number]: Dog;  // 数字索引对应的Dog 必须是 字符串索引返回值的 子类型
}

// 因为同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。
// 因为使用number做索引时 最终还是会被转换为string 作为key值

接口:类类型

// 接口描述了类的公共部分,而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员。
// 只约束类 不用实现 之后的扩展的类 必须要有 currentTime 属性 和setTime方法
interface ClockInterface {
  currentTime: Date;
  setTime(d: Date):void; 
}

class Clock implements ClockInterface {
  currentTime: Date = new Date();
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number, ) { 

  }
}

接口的继承

interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.length = 1; // error Square上不存在length属性

// 可以继承多个接口

interface Shape {
  color: string;
}

interface PenStroke {
  penWidth: number;
}

interface Square extends Shape, PenStroke {
  sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

接口:混合类型

// 可以同时当做函数和对象使用 还能有额外的属性
interface Counter { 
  (start: number): string;  // 当做函数接口
  interval: number; // 额外的属性
  reset(): void; // 额外的方法 
}

function getCounter(): Counter {
  let counter = <Counter>function (start: number) { };
  counter.interval = 123;
  counter.reset = function () { };
  return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

接口继承类

当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)

class Control {
  private state: any;
}

interface SelectableControl extends Control {
  select(): void;
}

class Button extends Control implements SelectableControl {
  select() { }
}

// 接口SelectableControl继承了Control类  Control类拥有属性或受保护的成员
// 那么 接口SelectableControl只能由Control或 ontrol的子类来实现

// Error: Property 'state' is missing in type 'Image'. 
class Image implements SelectableControl { 
  select() { }
}