阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 接口实现与类类型

接口实现与类类型

作者:陈川 阅读数:35669人阅读 分类: TypeScript

接口实现与类类型

TypeScript中的接口和类类型是构建复杂类型系统的核心工具。接口定义契约,类实现这些契约,两者结合能创建出强类型且可扩展的代码结构。

接口的基本实现

类可以通过implements关键字实现一个或多个接口。当类实现接口时,必须包含接口中定义的所有属性和方法:

interface Animal {
  name: string;
  makeSound(): void;
}

class Dog implements Animal {
  name: string;
  
  constructor(name: string) {
    this.name = name;
  }
  
  makeSound() {
    console.log("Woof!");
  }
}

未实现接口全部成员会导致编译错误:

class Cat implements Animal {
  // 错误: 缺少'makeSound'属性
  name: string;
}

可选属性和只读属性

接口可以定义可选属性和只读属性,实现类需要遵守这些约束:

interface User {
  readonly id: number;
  username: string;
  age?: number;
}

class RegisteredUser implements User {
  readonly id: number;
  username: string;
  
  constructor(id: number, username: string) {
    this.id = id;
    this.username = username;
  }
  
  // age是可选的,可以不实现
}

实现多个接口

一个类可以实现多个接口,用逗号分隔:

interface Loggable {
  log(): void;
}

interface Serializable {
  serialize(): string;
}

class Document implements Loggable, Serializable {
  log() {
    console.log("Logging document");
  }
  
  serialize() {
    return "Serialized document";
  }
}

接口继承与类实现

接口可以继承其他接口,类实现时需要满足继承链上的所有要求:

interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

class MySquare implements Square {
  color: string = "red";
  sideLength: number = 10;
}

类类型与构造函数签名

接口不仅可以描述实例结构,还可以描述类构造函数:

interface ClockConstructor {
  new (hour: number, minute: number): ClockInterface;
}

interface ClockInterface {
  tick(): void;
}

function createClock(
  ctor: ClockConstructor,
  hour: number,
  minute: number
): ClockInterface {
  return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
  constructor(h: number, m: number) {}
  
  tick() {
    console.log("beep beep");
  }
}

class AnalogClock implements ClockInterface {
  constructor(h: number, m: number) {}
  
  tick() {
    console.log("tick tock");
  }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

静态部分与实例部分

TypeScript中的类有静态部分和实例部分。实现接口时,类只检查实例部分:

interface Person {
  name: string;
  greet(): void;
}

class Employee implements Person {
  static company = "ACME";
  
  constructor(public name: string) {}
  
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
}

抽象类与接口

抽象类可以实现接口,但不一定要实现所有成员,可以由派生类完成:

interface Vehicle {
  startEngine(): void;
  stopEngine(): void;
}

abstract class Car implements Vehicle {
  abstract startEngine(): void;
  
  stopEngine() {
    console.log("Engine stopped");
  }
}

class SportsCar extends Car {
  startEngine() {
    console.log("Vroom!");
  }
}

接口中的索引签名

类实现带有索引签名的接口时,需要满足索引签名的约束:

interface StringArray {
  [index: number]: string;
}

class MyArray implements StringArray {
  [index: number]: string;
  
  constructor() {
    this[0] = "first";
    this[1] = "second";
  }
}

混合类型接口

接口可以描述同时作为函数和对象的类型:

interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}

function getCounter(): Counter {
  let counter = <Counter>function (start: number) {
    return "Started at " + start;
  };
  counter.interval = 123;
  counter.reset = () => {
    console.log("Reset counter");
  };
  return counter;
}

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

接口与类类型的类型检查

TypeScript使用结构性子类型进行类型检查,只要形状匹配就认为类型兼容:

interface Point {
  x: number;
  y: number;
}

class Point2D {
  constructor(public x: number, public y: number) {}
}

let p: Point = new Point2D(1, 2); // 有效

泛型类实现泛型接口

泛型类可以实现泛型接口,类型参数可以不同:

interface Pair<T, U> {
  first: T;
  second: U;
}

class StringNumberPair implements Pair<string, number> {
  constructor(public first: string, public second: number) {}
}

class GenericPair<T, U> implements Pair<T, U> {
  constructor(public first: T, public second: U) {}
}

接口中的私有成员

从TypeScript 3.8开始,接口可以声明私有字段,但实现类必须在同一文件中:

interface PrivateExample {
  #secret: string;
  reveal(): string;
}

class SecretKeeper implements PrivateExample {
  #secret: string;
  
  constructor(secret: string) {
    this.#secret = secret;
  }
  
  reveal() {
    return this.#secret;
  }
}

接口与类类型的进阶模式

结合接口和类类型可以实现更复杂的模式,如工厂模式:

interface Product {
  operation(): string;
}

abstract class Creator {
  public abstract factoryMethod(): Product;
  
  public someOperation(): string {
    const product = this.factoryMethod();
    return `Creator: ${product.operation()}`;
  }
}

class ConcreteProduct1 implements Product {
  operation(): string {
    return "Result of ConcreteProduct1";
  }
}

class ConcreteCreator1 extends Creator {
  public factoryMethod(): Product {
    return new ConcreteProduct1();
  }
}

接口合并与类实现

当接口合并时,类需要实现合并后的所有成员:

interface Box {
  height: number;
}

interface Box {
  width: number;
}

class CardboardBox implements Box {
  height: number = 0;
  width: number = 0;
}

类表达式实现接口

类表达式也可以实现接口:

interface Runnable {
  run(): void;
}

const MyRunner = class implements Runnable {
  run() {
    console.log("Running");
  }
};

const runner = new MyRunner();
runner.run();

接口中的调用签名与构造签名

接口可以同时包含调用签名和构造签名:

interface CallOrConstruct {
  new (s: string): Date;
  (n?: number): number;
}

function getDate(): CallOrConstruct {
  function buildDate(s: string) {
    return new Date(s);
  }
  
  buildDate.now = function(n?: number) {
    return n || Date.now();
  };
  
  return buildDate as CallOrConstruct;
}

const MyDate = getDate();
const d = new MyDate("2023-01-01");
const timestamp = MyDate();

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌