Javascript

TypeScript – interfejsy

Interfejsy pozwalają podnieść poziom abstrakcji i uzyskać luźniejsze powiązania pomiędzy klasami w naszych aplikacjach. Pozwala to projektować zależności nie ograniczając się do konkretnego typu – wystarczy, aby dany typ spełniał zadany interfejs.

Co to znaczy – „spełniał interfejs”?

Interfejsy są kontraktem – to znaczy, jeżeli dana klasa implementuje konkretny interfejs to zobowiązuje się ona do spełnienia jego wszystkich wymogów. Jakie są wymogi? Najczęściej ograniczają się one do utworzenia metod o konkretnej sygnaturze. Język TypeScript pozwala nam dodatkowo wymuszać m.in. składowe klas.

Składnia

Jako przykład stworzymy interfejs, który wymusza na wszystkich klasach, które go implementują:

  • metodę o nazwie order(),
  • składową o nazwie price.

Przykład interfejsu:


interface Orderable {
    price: number;
    order(): void;
}

Przykład klasy implementującej podany interfejs:


class Pizza implements Orderable {
    public price: number;
    public order(): void {}
}

Możemy zauważyć, że aby zadeklarować nowy interfejs korzystamy ze słowa kluczowego interface, natomiast aby wymusić na klasie jego implementację – słowo implements. To szczególnie powinno cieszyć programistów języka Java, którzy zdążyli się do tych słów przyzwyczaić.


Co w przypadku, kiedy klasa powinna implementować wiele interfejsów?


Na szczęście i w tym wypadku, nic nie stoi nam na przeszkodzie. Kolejne interfejsy wystarczy oddzielać przecinkami w następujący sposób:


class Pizza implements Orderable, Edible

Dziedziczenie interfejsów

Interfejsy, podobnie jak klasy – możemy dziedziczyć. Wykorzystujemy do tego słowo kluczowe extends:


interface Food extends Orderable, Edible

Interfejsy a funkcje anonimowe

Dzięki elastyczności języka JavaScript, tworzenie funkcji anonimowych jest bardzo proste. Przykład:


let fn = (x: number, y: number): number => x / y;

W jaki sposób, przy pomocy interfejsu, wymusić określony typ zmiennej przechowującej tego typu funkcję? Rozwiązanie:


interface Function {
    (x: number, y: number): number;
}

let fn: Function;
fn = (x: number, y: number): number => x / y;

Składowe opcjonalne

Jeżeli zachodzi taka potrzeba, niektóre zmienne możemy oznaczyć jako opcjonalne. Służy do tego znak ?:


interface Person {
    name: string;
    age?: number;
}

function addPerson(person: Person) {
    // do some stuff here
}

let person: Person;
person = {
    name: "John"
};
addPerson(person);

Powyższy kod skompiluje się, pomimo że obiekt person nie posiada składowej age.

Podsumowanie

Celem dzisiejszego wpisu było zaprezentowanie składni i możliwości interfejsów w języku TypeScript. Serdecznie zachęcam do przeczytania również poprzedniego wpisu dotyczącego klas – tutaj.