TypeScript: TypeScript 类与接口

最后更新:2026-08-26

类和接口是 TypeScript 面向对象编程的两大支柱——类提供实现,接口定义契约。当类实现接口时,TypeScript 会确保类满足接口规定的所有要求。

1. 类实现接口(implements)

(1) 基本语法

TYPESCRIPT
interface Printable {
  toString(): string;
}

class User implements Printable {
  constructor(public name: string, public age: number) {}

  toString(): string {
    return `${this.name},${this.age}岁`;
  }
}

let user = new User("Charlie", 20);
console.log(user.toString());  // "Charlie,20岁"

(2) 实现接口的意义

接口是"契约"——类实现接口就承诺"我会提供接口要求的所有属性和方法":

TYPESCRIPT
interface Animal {
  name: string;
  speak(): string;
  move(distance: number): void;
}

class Dog implements Animal {
  constructor(public name: string) {}

  speak(): string {
    return "汪汪!";
  }

  move(distance: number): void {
    console.log(`${this.name} 移动了 ${distance} 米`);
  }
}

// ❌ 缺少接口要求的成员会报错
// class Cat implements Animal {
//   constructor(public name: string) {}
//   // 缺少 speak 和 move → 编译错误
// }

(3) 多接口实现

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

TYPESCRIPT
interface Serializable {
  serialize(): string;
}

interface Comparable {
  compareTo(other: this): number;
}

class Score implements Serializable, Comparable {
  constructor(public value: number) {}

  serialize(): string {
    return JSON.stringify({ value: this.value });
  }

  compareTo(other: Score): number {
    return this.value - other.value;
  }
}

let s1 = new Score(90);
let s2 = new Score(85);

console.log(s1.serialize());       // '{"value":90}'
console.log(s1.compareTo(s2));     // 5(正数表示 s1 > s2)

▶ 示例:用接口定义统一的API

TYPESCRIPT
interface Repository<T> {
  findById(id: number): T | null;
  findAll(): T[];
  save(entity: T): void;
  delete(id: number): boolean;
}

interface User {
  id: number;
  name: string;
  email: string;
}

class UserRepository implements Repository<User> {
  private users: User[] = [];

  findById(id: number): User | null {
    return this.users.find(u => u.id === id) ?? null;
  }

  findAll(): User[] {
    return [...this.users];
  }

  save(entity: User): void {
    let index = this.users.findIndex(u => u.id === entity.id);
    if (index >= 0) {
      this.users[index] = entity;  // 更新
    } else {
      this.users.push(entity);     // 新增
    }
  }

  delete(id: number): boolean {
    let len = this.users.length;
    this.users = this.users.filter(u => u.id !== id);
    return this.users.length < len;
  }
}

let repo = new UserRepository();
repo.save({ id: 1, name: "Charlie", email: "xiao@example.com" });
repo.save({ id: 2, name: "Diana", email: "hong@example.com" });

console.log(repo.findById(1)?.name);  // "Charlie"
console.log(repo.findAll().length);   // 2
▶ 试一试

输出:

TEXT 📖 仅展示
Charlie
2

2. 接口继承类

TypeScript 的独特特性——接口可以继承类的成员定义(只继承类型声明,不继承实现):

TYPESCRIPT
class Control {
  private state: string = "active";

  protected getState(): string {
    return this.state;
  }
}

// 接口继承类——只继承类型签名
interface Selectable extends Control {
  select(): void;
}

// 类实现接口时必须提供所有成员
class Dropdown implements Selectable {
  private state: string = "active";  // 必须自己实现 private 成员

  protected getState(): string {
    return this.state;
  }

  select(): void {
    console.log("已选中:" + this.getState());
  }
}
💡 用途: 接口继承类主要在复杂类层次中用于描述"具有某个类结构同时有额外能力"的类型。日常开发中用得不多。


3. 抽象类(abstract)

抽象类是"半成品类"——它提供部分实现,子类必须补全剩余部分:

(1) 基本语法

TYPESCRIPT
abstract class Shape {
  // 抽象方法——没有实现,子类必须实现
  abstract getArea(): number;
  abstract getPerimeter(): number;

  // 具体方法——有实现,子类直接继承
  describe(): string {
    return `面积:${this.getArea().toFixed(2)},周长:${this.getPerimeter().toFixed(2)}`;
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }

  getPerimeter(): number {
    return 2 * Math.PI * this.radius;
  }
}

class Rectangle extends Shape {
  constructor(public width: number, public height: number) {
    super();
  }

  getArea(): number {
    return this.width * this.height;
  }

  getPerimeter(): number {
    return 2 * (this.width + this.height);
  }
}

// ❌ 抽象类不能直接实例化
// let shape = new Shape();

let circle = new Circle(5);
let rect = new Rectangle(4, 6);

console.log(circle.describe());  // "面积:78.54,周长:31.42"
console.log(rect.describe());    // "面积:24.00,周长:20.00"

(2) 抽象类 vs 接口

特性 抽象类 接口
实现方法 可以有具体实现 不能有任何实现
构造函数 可以有 不能有
多继承 只能单继承 可以多继承(extends)
访问修饰符 支持 public/private/protected 属性默认 public
实例化 不能直接实例化 不能实例化(纯类型)
运行时存在 是(编译为 JS 类) 否(纯类型声明)

(3) 什么时候用抽象类

(4) 什么时候用接口

▶ 示例:抽象类实现模板方法模式

TYPESCRIPT
abstract class DataParser {
  // 模板方法——定义算法骨架
  parse(input: string): string {
    let raw = this.read(input);
    let validated = this.validate(raw);
    let transformed = this.transform(validated);
    return this.format(transformed);
  }

  // 具体方法——所有子类共享
  private read(input: string): string {
    return input.trim();
  }

  // 抽象方法——子类各自实现
  protected abstract validate(data: string): string;
  protected abstract transform(data: string): string;

  // 钩子方法——子类可选覆写
  protected format(data: string): string {
    return data;
  }
}

class UpperParser extends DataParser {
  protected validate(data: string): string {
    if (data.length === 0) throw new Error("输入为空");
    return data;
  }

  protected transform(data: string): string {
    return data.toUpperCase();
  }
}

class ReverseParser extends DataParser {
  protected validate(data: string): string {
    return data;
  }

  protected transform(data: string): string {
    return data.split("").reverse().join("");
  }

  protected format(data: string): string {
    return `[反转] ${data}`;
  }
}

let upper = new UpperParser();
let reverse = new ReverseParser();

console.log(upper.parse("  hello world  "));     // "HELLO WORLD"
console.log(reverse.parse("  hello world  "));    // "[反转] dlrow olleh"
▶ 试一试

输出:

TEXT 📖 仅展示
HELLO WORLD
[反转] dlrow olleh

4. 类作为类型使用

类定义本身就是一个类型——可以用类名作为变量的类型:

(1) 类的类型含义

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

  distanceTo(other: Point): number {
    return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
  }
}

// 类作为类型——接受 Point 实例或结构兼容的对象
let p1: Point = new Point(1, 2);
let p2: Point = { x: 3, y: 4 };   // ✅ 结构兼容(但不包含方法!)

console.log(p1.distanceTo(p2));    // ✅ p1 有 distanceTo 方法
// p2.distanceTo(p1);              // ❌ p2 只有 x 和 y,没有方法
⚠️ 注意: 类的类型部分只包含实例属性和方法签名。用结构兼容的对象赋值时,方法不会被包含——只有属性匹配。需要方法时应该用 new Point() 创建实例。

(2) 类类型 vs typeof 类

TYPESCRIPT
class Factory {
  static create(): Factory {
    return new Factory();
  }

  constructor(public name: string) {}
}

// Factory 类型——实例类型
let instance: Factory = new Factory("产品");

// typeof Factory 类型——类本身(构造函数类型)
let FactoryClass: typeof Factory = Factory;
let another = FactoryClass.create();  // ✅ 调用静态方法

❓ 常见问题

Q implements 和 extends 有什么区别?
A implements 是"实现接口"——类承诺提供接口要求的所有成员,但不继承任何实现代码。extends 是"继承类"——子类获得父类的所有实现代码,并可以覆写。一个类可以 implements 多个接口,但只能 extends 一个父类。
Q 抽象类和接口该用哪个?
A 简单规则——如果多个类需要共享实现代码,用抽象类;如果只需要定义"能做什么"的契约,用接口。可以两者结合——接口定义能力,抽象类提供部分实现。
Q 类实现接口时可以有多余的成员吗?
A 可以。类实现接口只要求"至少有接口要求的成员",多余成员完全合法。例如 interface Printable { print(): void }class Document implements Printable { print() {...}; save() {...} }——Document 多了 save 方法,但完全合法。
Q 接口能继承抽象类吗?
A 可以。interface ISelect extends AbstractControl {} 合法——接口会继承抽象类的所有成员签名(包括 private 成员的签名)。但实现这个接口的类必须自己提供所有成员的实现,包括 private 成员。

📖 小节

📝 作业

  1. 基础题(难度⭐):定义 Loggable 接口(log 方法),让 User 类和 Product 类分别实现它。创建实例并调用 log 方法。
  2. 进阶题(难度⭐⭐):定义抽象类 Vehicle(brand 属性、abstract start 方法、concrete describe 方法),然后创建 CarBike 子类分别实现 start。写一个函数接受 Vehicle 类型参数调用 describe。
  3. 挑战题(难度⭐⭐⭐):设计一个 SortableCollection<T> 接口(length 属性、compare 方法、swap 方法),让 NumberCollection 类实现它。然后在 Sorter 抽象类中实现冒泡排序算法(依赖接口方法),子类只需提供 compare 和 swap 的具体实现。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏