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

类与接口的关系

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

在TypeScript中,类和接口是构建复杂类型系统的核心工具。类提供具体的实现,而接口定义行为的契约,二者通过多种方式协作,共同实现代码的抽象与复用。

类的定义与实现

类是面向对象编程的基础,用于描述对象的属性和方法。TypeScript中的类支持继承、封装和多态等特性。例如:

class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

接口的基本概念

接口纯粹是类型定义的工具,不包含具体实现。它用于描述对象应该具有的形状:

interface Movable {
  move(distance: number): void;
}

类实现接口

类可以通过implements关键字实现一个或多个接口,这强制类必须满足接口定义的契约:

class Car implements Movable {
  move(distance: number) {
    console.log(`Car moved ${distance}km.`);
  }
}

接口继承类

TypeScript允许接口继承类的成员定义(不包括实现),这在需要复用类结构时非常有用:

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

interface Point3D extends Point {
  z: number;
}

const point: Point3D = { x: 1, y: 2, z: 3 };

类类型与接口的异同

特性 接口
实现 包含具体实现 只有类型定义
运行时存在
可实例化
继承 单继承 多继承

接口扩展类时的特殊情况

当接口继承包含私有或受保护成员的类时,只有该类的子类才能实现这个接口:

class Control {
  private state: any;
}

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

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

// 错误:缺少私有成员state
class TextBox implements SelectableControl {
  select() {}
}

混合类型接口

接口可以描述函数、对象和索引签名的组合,这种灵活性在处理复杂场景时特别有用:

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

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

抽象类与接口的对比

抽象类介于普通类和接口之间,可以包含部分实现:

abstract class Department {
  constructor(public name: string) {}

  abstract printMeeting(): void;
}

class AccountingDepartment extends Department {
  printMeeting() {
    console.log('Accounting meeting');
  }
}

接口合并的特性

同名的接口会自动合并,这在扩展第三方类型时很常见:

interface Box {
  height: number;
}

interface Box {
  width: number;
}

// 最终Box接口包含height和width
const box: Box = { height: 1, width: 2 };

类静态部分与实例部分的区别

类有静态部分和实例部分,接口只能约束实例部分:

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);
}

使用接口描述函数类型

接口可以描述函数签名,这在定义回调时特别有用:

interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc = function(src, sub) {
  return src.search(sub) > -1;
};

可索引类型接口

接口可以描述数组和字典等可索引类型:

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

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

接口与类型别名的区别

虽然接口和类型别名有时可以互换,但它们有本质区别:

type Alias = { num: number }
interface Interface {
  num: number;
}

// 类型别名不能extends或implements
class A implements Interface {
  num = 1;
}

接口描述构造函数

通过特殊的构造签名,接口可以描述构造函数:

interface SomeConstructor {
  new (s: string): SomeInterface;
}

interface SomeInterface {
  doSomething(): void;
}

function createInstance(ctor: SomeConstructor, s: string): SomeInterface {
  return new ctor(s);
}

接口的readonly属性

接口可以定义只读属性,增强类型安全性:

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

let p1: Point = { x: 10, y: 20 };
p1.x = 5; // 错误!

类实现多个接口

TypeScript支持一个类实现多个接口,这比多重继承更灵活:

interface Flyable {
  fly(): void;
}

interface Swimmable {
  swim(): void;
}

class Duck implements Flyable, Swimmable {
  fly() { console.log('Flying'); }
  swim() { console.log('Swimming'); }
}

接口中的可选属性

接口属性可以标记为可选,增加灵活性:

interface SquareConfig {
  color?: string;
  width?: number;
}

function createSquare(config: SquareConfig) {
  // ...
}

接口描述复杂对象

接口可以描述包含多种类型的复杂对象结构:

interface NestedObject {
  id: string;
  metadata: {
    createdAt: Date;
    updatedAt?: Date;
    tags: string[];
  };
}

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

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

上一篇:多态与this类型

下一篇:构造器函数类型

前端川

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