PorównaniePorównania

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.

Na tej stronie

Porównanie w tabeli

#

Przykład

#
TypeScript
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())
Wynik
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

#
Składnia
class Potomna extends Bazowa { … }
class Klasa implements Interfejs { … }

Więcej przykładów

#
extends dziedziczy kod, implements nie
TypeScript
class Shape {
  describe(): string {
    return 'Figura'
  }
}

class Circle extends Shape {}

const circle = new Circle()
console.log(circle.describe())
console.log(circle instanceof Shape)
Wynik
Figura
true
implements wymusza własną implementację
TypeScript
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.
  • implements sprawdza tylko typy. Parametry metod i tak musisz otypować w samej klasie, kompilator nie przejmuje ich z interfejsu.
  • Głębokie łańcuchy extends trudno utrzymać. Często lepsza jest kompozycja: klasa przyjmuje inny obiekt jako zależność, zamiast dziedziczyć po nim.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.