I'm learning TypeScript about extending the interface. I unintentionally recognized that TypeScript allows extending interface from multiple classes. That made me surprised and I have researched a lot to find more information about but until now, I have not been able to answer questions.
I am wondering that: although TypeScript prevents class inheriting from multi-classes (class has 2 or more direct base classes), why does it permit one interface to extend directly from multiple classes like that code below:
class Student{
name:string = ''
}
class Employee {
salary:number =0
}
interface Work_Study extends Student,Employee{
description:string;
}
When you write a class
declaration in TypeScript like
class Student {
name: string = ''
}
it brings into scopes two things named Student
. One is the class constructor value that exists at runtime in JavaScript. It's an object named Student
and you can write new Student()
to construct a new class instance value. The other is the class instance type that exists only in TypeScript's type system. It's a type named Student
and you can write let student: Student
to tell TypeScript that the type of student
is the instance type of the Student
class. Even though they share a name and are related, they are not the same thing.
TypeScript doesn't get confused about which thing you're referring to because values and types live in different syntactic contexts in TypeScript. If you write x = new X()
, that X
is definitely a value, not a type. If you write let x: X;
, that X
is definitely a type, not a value. If you write interface Z extends X {}
, that X
is definitely a type, not a value.
See the TypeScript handbook documentation for more details.
It's also important to note that the class instance type behaves exactly like an interface. It's not declared using the interface
keyword, but it behaves the same. Indeed, the Student
declaration above is quite similar to the pair
interface Student {
name: string
}
const Student: new () => Student = class {
name: string = ""
};
where the two things named Student
are defined explicitly and separately.
If we put those together, we can understand what
class Student {
name: string = ''
}
class Employee {
salary: number = 0
}
interface Work_Study extends Student, Employee {
description: string;
}
is doing. The interface
declaration with the extends
clause is just declaring a new interface which inherits from the Student
and Employee
types. It has nothing whatsoever to do with the Student
and Employee
constructors. It's exactly the same as
interface Student {
name: string
}
interface Employee {
salary: number;
}
interface Work_Study extends Student, Employee {
description: string;
}
And multiple inheritance of interfaces is unproblematic.
On the other hand, something like
class Work_Study extends Student, Employee {
description: string = "oops"
}
is different, in that it's a class declaration and involves the value space. It's invalid because that's the JavaScript extends
clause which only allows extending a single parent class. Multiple inheritance in JavaScript classes is prohibited (to avoid the diamond problem where it's ambiguous which implementation to use).
While class Work_Study extends Student, Employee {}
and interface Work_Study extends Student, Employee {}
look similar, they are in completely different syntactic contexts, and behave differently. The former is illegal multiple class inheritance, while the latter is legal multiple interface inheritance.