Communardo Software GmbH, Kleiststraße 10 a, D-01129 Dresden
0800 1 255 255

TypeScript-Tipps: Überladene Funktionen durch Interfaces beschreiben

Wie lassen sich Schnittstellen beschreiben, die überladene Funktionen als Parameter entgegennehmen oder als Wert zurückgeben? Der Beitrag zeigt anhand eines Beispiels, wie dies in TypeScript ohne Probleme gelingt.

TypeScript bie­tet enor­mes Potential, den Entwickler wäh­rend der Entwicklung durch Typisierung zu unter­stüt­zen. Es ist damit klar das bes­sere JavaScript. Die Reihe TypeScript-Tipps setzt ein­zelne Features der Sprache in den Fokus. Heute sind dies Interfaces.

Wir bauen auf einem vor­he­ri­gen Beitrag der Reihe TypeScript-Tipps auf und schauen erneut auf über­la­dene Funktionen. Wie las­sen sich Schnittstellen beschrei­ben, die über­la­dene Funktionen als Parameter ent­ge­gen­neh­men oder als Wert zurück­ge­ben? Der Beitrag zeigt anhand eines Beispiels, wie dies in TypeScript ohne Probleme gelingt.

Wir bauen eine Factory für Funktionen

Schauen wir kurz auf den Code, der im Blogbeitrag "TypeScript-Tipps: Funktionen über­la­den" ent­stan­den ist:

Zur Erinnerung: der obige Code dekla­riert die zwei­fach über­la­dene Funktion AddOne unter Verwendung von Function Types. Wen die Herleitung und die Hintergründe inter­es­sie­ren, der schaut am bes­ten kurz in den Blogbeitrag rein.

Nehmen wir an, die Funktion AddOne kann unter­schied­li­che Implementierungen besit­zen und soll daher durch eine Art Fabrikfunktion bereit­ge­stellt wer­den:

Die erste Zeile dekla­riert AddOneFactory als Funktion, die wie­derum eine Funktion mit Signatur (value: any) => any zurück­gibt. Die zweite Zeile imple­men­tiert diese Fabrikfunktion so, dass als Ergebnis unsere AddOne-Funktion zurück­ge­ge­ben wird. Diese könnte nun jeder­zeit durch eine andere Implementierung ersetzt wer­den.

So sieht die Verwendung der Fabrikfunktion aus:

Der Aufruf von AddOneFactory() gibt eine AddOne-Funktion zurück, die anschlie­ßend auf­ge­ru­fen wer­den kann.

Wo ist der Haken?

Wir haben durch die Deklaration der Fabrikfunktion jeg­li­che Typinformationen ver­lo­ren, die wir der kon­kre­ten Implementierung von AddOne mit­ge­ge­ben hat­ten. Sowohl Parameter als auch Rückgabewert sind vom Typ any.

Aber das geht bes­ser.

Funktionen durch Interfaces beschreiben

Interfaces die­nen in TypeScript dazu, Datentypen zu beschrei­ben, ohne (im Unterschied zu Klassen) eine Implementierung vor­zu­ge­ben.

Ein inter­es­san­tes Feature von Interfaces ist die Beschreibung von Function Types, also Signaturen von Funktionen. Fangen wir mit einem ein­fa­chen Beispiel an:

Die Syntax ist etwas gewöh­nungs­be­dürf­tig. Das Interface IFunctionTypeDescriptor beschreibt in Zeile 2 die Signatur einer Funktion ohne Namen: (): string. Anschließend wird in Zeile 5 eine Variable func dekla­riert, die vom Typ IFunctionTypeDescriptor ist. Der Wert die­ser Variable muss nun genau der im Interface dekla­rier­ten Signatur ent­spre­chen, also eine Funktion ohne Parameter, die Text zurück­gibt.

In Zeile 6 wird eine sol­che Funktion zuge­wie­sen. An die Lambda-Schreibweise soll­ten sich alle SharePoint Framework-Erfahrenen inzwi­schen gewöhnt haben.

In Zeile 7 nun wird die Funktion auf­ge­ru­fen und die Ausgabe erfolgt.

Und warum betrei­ben wir die­sen Aufwand eigent­lich? Weil wir damit wie­der ein­mal Fehler früh­zei­tig erken­nen kön­nen. Gibt bei­spiels­weise die Funktion func kei­nen Text zurück, son­dern eine Zahl, dann weist Visual Studio Code wäh­rend der Entwicklung dar­auf hin:

Der gefor­derte Rückgabewert string und der in der Implementierung von func ver­wen­dete Typ num­ber sind nicht kom­pa­ti­bel.

Was aber, wenn sowohl string, als auch num­ber erlaubt sein sol­len?

Überladene Funktionen durch Interfaces beschreiben

Jetzt schließt sich der Kreis zurück zu unse­rer AddOne-Fabrikfunktion. Wir kön­nen ein Interface ver­wen­den, um diese Funktion kor­rekt zu typi­sie­ren.

Vorab das kom­plette Code-Beispiel, wel­ches wir der Reihe nach betrach­ten:

Die Zeilen 1–9 sind unver­än­dert.

In den Zeilen 11–14 wird jetzt mit Hilfe eines Interfaces und Function Types beschrie­ben, wel­che über­la­dene Funktion unsere Fabrikfunktion erzeugt. Hier sind alle über­la­de­nen Signaturen der erzeug­ten Funktion auf­ge­führt.

In Zeile 16 wird die Fabrikfunktion BetterAddOneFactory dekla­riert. Diese gibt selbst eine Funktion zurück, die wie durch IAddOneFactoryResult beschrie­ben über­la­den ist.

In Zeile 17 wird wie gehabt die Fabrikfunktion imple­men­tiert.

Und warum machen wir das Ganze? Diese Frage wird in Zeile 20 beant­wor­tet, wenn wir uns die Autovervollständigung in Visual Studio Code anschauen:

Die von der Fabrikfunktion erzeugte Funktion ist kor­rekt typi­siert. Außerdem wird sicher­ge­stellt, dass die von der Fabrikfunktion erzeug­ten Implementierungen immer wie erwar­tet über­la­den sind.

Zusammenfassung

Wir haben gelernt, wie sich über­la­dene Funktionen durch Interfaces beschrei­ben las­sen.

Dabei haben wir eine Fabrikfunktion als Anwendungsbeispiel betrach­tet. Diese Fabrikfunktion erzeugt über­la­dene Funktionen mit klar defi­nier­ten Signaturen, die zur Entwicklungszeit auf Richtigkeit prüf­bar sind. Dafür machen wird uns zunutze, dass TypeScript-Interfaces über­la­dene Funktionen beschrei­ben kön­nen.

Happy Coding!

Related Posts

Pin It on Pinterest