我正在学习有关扩展接口的 TypeScript。我无意中意识到 TypeScript 允许从多个类扩展接口。这让我感到惊讶,我进行了很多研究以找到更多信息,但直到现在,我还无法回答问题。
我想知道:虽然 TypeScript 阻止类从多个类继承(类有 2 个或更多直接基类),但为什么它允许一个接口直接从多个类扩展,如下代码所示:
```typescript
class Student{
name:string = ''
}
class Employee {
salary:number =0
}
interface Work_Study extends Student,Employee{
description:string;
}
```
一般来说,使用继承通常被认为是一种不好的做法。您需要记住一些好的做法:
接口隔离原则(ISP):“任何代码都不应被迫依赖于它不使用的方法”。
组合重用原则 (CRP):“类应该通过其组合(通过包含实现所需功能的其他类的实例)而不是从基类或父类继承来支持多态行为和代码重用。”
不允许使用多重继承,以避免钻石问题,并鼓励开发者遵守CRP原则。这是 ECMAScript 委员会关于 JavaScript 继承的设计决定。
关于您的问题 1. 您可以扩展多个接口以符合ISP的要求。例如:
interface Disposable {
dispose: () => void;
}
interface Serializable {
serialize: () => string;
}
class Student implements Disposable, Serializable {
name:string = '';
somethingElse: number = 0;
serialize() {
return JSON.stringify(this);
}
dispose() {
// dispose logic
}
}
如果只允许你实现一个接口,你就会鼓励开发者打破 ISP 原则。
使用多个接口意味着当你实现应用程序的其他部分时,这些部分不需要与
Student
耦合;它们只能与它们需要的方法耦合:
function cleanUp(something: Disposable) {
something.dispose();
}
function serialzie(something: Serializable) {
return something.serialize();
}
关于您的问题2和3:
是的,实现多个接口很常见。 这里是 TypeScript 代码本身的示例。
是的,与2相同。只有一个限制,钻石问题:
interface Student {
name:string;
somethingElse: number;
}
interface Employee {
salary:number;
somethingElse: string;
}
// 'WorkStudy' cannot simultaneously extend types 'Student' and 'Employee'.
// Named property 'somethingElse' of types 'Student' and 'Employee' are not identical.
interface WorkStudy extends Student, Employee{
description:string;
}
如果您想重用代码,唯一的选择是使用组合而不是继承:
interface IStudent {
name:string;
}
interface IEmployee {
salary:number;
}
class Student implements IStudent {
constructor(public name: string) {}
}
class Employee implements IEmployee {
constructor(public salary: number) {}
}
class WorkStudy implements IStudent, IEmployee{
private _student: IStudent;
private _employee: IEmployee;
constructor(
public description: string,
student: IStudent,
employee: IEmployee
) {
this._employee = employee;
this._student = student;
}
get salary() {
return this._employee.salary;
}
get name() {
return this._student.name;
}
}
因此,您唯一的选择就是遵守 CRP。