extends vs implements
extends dziedziczy pola i kod z klasy albo interfejsu bazowego, a implements tylko wymusza, żeby klasa miała metody i pola z interfejsu, bez przejmowania ich kodu.
Porównanie w tabeli
#Działa między
- extends (interfejsy)
- Dwiema klasami (lub dwoma interfejsami)
- implements
- Klasą a interfejsem
Dziedziczy kod (pola, metody)
- implements
- Nie, tylko kształt do zaimplementowania
Liczba naraz
- extends (interfejsy)
- Jedna klasa bazowa
- implements
- Wiele interfejsów naraz
Dostęp do super()
- implements
- Nie dotyczy
Brakująca metoda
- extends (interfejsy)
- Dziedziczona z klasy bazowej
- implements
- Błąd:
incorrectly implements interface
Typowe użycie
- extends (interfejsy)
- Wspólna logika w klasach pochodnych
- implements
- Kontrakt dla niezależnych klas
Przykład
#class Person {
constructor(public name: string) {}
greet(): string {
return `Cześć, jestem ${this.name}`
}
}
interface Scorable {
score(): number
}
class Student extends Person implements Scorable {
constructor(name: string, private points: number) {
super(name)
}
score(): number {
return this.points
}
}
const student = new Student('Ania', 92)
console.log(student.greet())
console.log(student.score())Cześć, jestem Ania 92
Definicja i zastosowanie
#Obu słów używasz w deklaracji klasy, żeby powiązać ją z innym typem, i obie sprawdza kompilator: jeśli klasa nie spełnia wymagań, zgłosi błąd. Klasa może rozszerzać tylko jedną klasę bazową, ale implementować kilka interfejsów naraz.
Różnica jest w tym, co klasa dostaje. extends między klasami dziedziczy prawdziwy kod: pola, metody i konstruktor klasy bazowej, które możesz wywołać przez super() albo nadpisać. implements nie dziedziczy żadnego kodu, tylko sprawdza na etapie kompilacji, że klasa sama zaimplementowała wszystko, co obiecuje interfejs. extends działa też między interfejsami, gdzie rozszerza listę wymaganych pól.
Gdy klasy mają dzielić wspólną logikę, np. wspólny konstruktor czy metodę pomocniczą, użyj extends. Gdy chcesz tylko zagwarantować, że różne, niepowiązane klasy mają określone metody, np. Comparable albo Serializable, użyj implements. Interfejsy opisujące możliwości łączą się lepiej niż głębokie dziedziczenie klas.
Składnia
#class Potomna extends Bazowa { … }
class Klasa implements Interfejs { … }Więcej przykładów
#class Shape {
describe(): string {
return 'Figura'
}
}
class Circle extends Shape {}
const circle = new Circle()
console.log(circle.describe())
console.log(circle instanceof Shape)Figura true
interface Scorable {
score(): number
}
class Exam implements Scorable {}
// Błąd: Class 'Exam' incorrectly implements interface 'Scorable'.
// Property 'score' is missing in type 'Exam' but required in type 'Scorable'.Dobre praktyki
#- Jedna klasa może implementować kilka interfejsów, ale rozszerzyć tylko jedną klasę. Jeśli potrzebujesz kilku niezależnych "zdolności", sięgnij po interfejsy.
implementssprawdza tylko typy. Parametry metod i tak musisz otypować w samej klasie, kompilator nie przejmuje ich z interfejsu.- Głębokie łańcuchy
extendstrudno utrzymać. Często lepsza jest kompozycja: klasa przyjmuje inny obiekt jako zależność, zamiast dziedziczyć po nim.
Powiązane hasła
#- extends (interfejsy)Rozszerzanie interfejsu o nowe pola, na bazie istniejącego.
- implementsDeklaracja, że klasa spełnia kontrakt opisany interfejsem.
- abstract classKlasa bazowa, której nie można utworzyć bezpośrednio, z metodami do uzupełnienia przez potomków.
- public, private, protectedModyfikatory dostępu określające, skąd można używać pól i metod klasy.
- interfaceNazwany opis kształtu obiektu, który można rozszerzać i łączyć.
Widzisz błąd albo brakuje przykładu? Napisz do nas.