在 TypeScript (TS) 中,接口(Interface)、继承(Inheritance)和抽象类(Abstract Class)是用于设计和组织代码的重要概念。它们虽然有一些相似之处,但各自的用途和功能不同。以下是它们之间的主要区别,以及如何设计和使用它们。
1. 接口(Interface)
接口在 TypeScript 中主要用于定义一个类型的契约,它可以定义对象的结构或类的方法、属性,而不提供实现。接口用于描述一个类应该遵守的规范,类似于其他语言中的接口概念。
设计和使用接口:
- 定义:接口通常定义对象或者类的结构,方法签名,属性等。
 - 实现:类可以通过 implements 关键字来实现接口。
 - 用途:接口可以用于保证类或对象符合某种结构,也可以用作函数参数的类型声明,确保函数的参数符合规定的结构。
示例:接口 
// 定义一个接口
interface Animal {
    name: string;
    sound(): void;  // 方法签名,接口不提供实现
}
// 类实现接口
class Dog implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sound() {
        console.log("Woof!");
    }
}
const dog = new Dog("Buddy");
dog.sound();  // 输出: Woof!
特点:
- 接口不能有实现:接口只能定义方法签名和属性,不能提供方法的实现。
 - 接口可以多重继承:一个接口可以继承多个接口,组合多个接口的属性和方法。
 
interface Animal {
    name: string;
}
interface Sound {
    sound(): void;
}
// 接口可以继承多个接口
interface Dog extends Animal, Sound {}
class Beagle implements Dog {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sound() {
        console.log("Bark!");
    }
}
2. 继承(Inheritance)
继承是面向对象编程中的一个重要概念。它允许子类继承父类的属性和方法,并且可以进行方法的重写(overriding)或扩展(extending)。在 TypeScript 中,继承通过 extends 关键字实现。
设计和使用继承:
- 子类继承父类:子类继承父类的属性和方法,可以重写父类的方法或扩展父类的功能。
 - 类的继承:继承是面向对象编程的核心概念,主要用来共享通用行为,同时保留灵活性。
示例:继承 
class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sound() {
        console.log("Some generic sound");
    }
}
// 子类继承父类
class Dog extends Animal {
    constructor(name: string) {
        super(name);  // 调用父类的构造函数
    }
    // 重写父类的方法
    sound() {
        console.log("Woof!");
    }
}
const dog = new Dog("Buddy");
dog.sound();  // 输出: Woof!
特点:
- 继承用于共享代码:通过继承,子类可以重用父类的属性和方法。
 - 可以重写方法:子类可以重写父类的方法来改变行为(方法的重写)。
 - 单继承:TypeScript 中的类支持单继承,即一个类只能继承另一个类。
 
3. 抽象类(Abstract Class)
抽象类是不能实例化的类。它可以包含抽象方法和具体实现的方法。抽象方法是没有实现的方法,子类必须实现这些抽象方法。抽象类用于创建一个通用的基类,强制子类提供一些实现,同时保留一些默认行为。
设计和使用抽象类:
- 抽象类不能被实例化:直接实例化抽象类会报错。
 - 包含抽象方法:抽象类可以包含抽象方法,子类必须重写这些方法。
 - 可以包含具体实现:抽象类也可以包含具有实现的方法,子类可以继承并重用这些方法。
示例:抽象类 
abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    // 抽象方法:子类必须实现
    abstract sound(): void;
    // 普通方法:子类可以直接继承
    move() {
        console.log(`${this.name} is moving.`);
    }
}
class Dog extends Animal {
    constructor(name: string) {
        super(name);  // 调用父类构造函数
    }
    // 实现抽象方法
    sound() {
        console.log("Woof!");
    }
}
const dog = new Dog("Buddy");
dog.sound();  // 输出: Woof!
dog.move();   // 输出: Buddy is moving.
特点:
- 抽象类不能实例化:抽象类不能直接创建对象,只能通过子类来实例化。
 - 包含抽象方法和具体实现:抽象类可以包含没有实现的抽象方法,也可以包含已经实现的普通方法。
 - 可以有构造函数:抽象类可以定义构造函数,子类可以通过 super() 调用。
 
总结和对比

截屏2025-02-05 14.44.03.png
使用场景:
- 接口(Interface):当你希望定义一个合同或结构,而不关心具体实现时使用接口。例如,定义类之间的共享 API,或定义函数参数的类型。
 - 继承(Inheritance):当你有多个类共享相同的功能和属性时,使用继承。它有助于减少代码重复,并且通过多态性(polymorphism)可以在运行时灵活地处理不同的类。
 - 抽象类(Abstract Class):当你希望提供一个默认的实现并要求子类必须实现某些方法时,使用抽象类。例如,定义一个基类来提供通用功能,而子类提供特定功能的实现。