Warum du nur noch TypeScript nutzen solltest ☝️

JavaScript ist tot, lang lebe TypeScript! Wie TypeScript dich aktiv unterstützt besseren und zuverlässigeren Code zu schreiben, erkläre ich dir in diesem Artikel 🎉

Warum du nur noch TypeScript nutzen solltest ☝️
Photo by Nangialai Stoman / Unsplash / Image

JavaScript, vermutlich kennt es jeder der bereits in der Webentwicklung zutun hatte. Auch wird jeder die Schmerzen kennen, die JavaScript auslöst und noch viel mehr werden die Probleme von JavaScript kennen. In diesem Artikel möchte ich dir zeigen welche Probleme JavaScript hat, welches davon am größten ist und wie TypeScript dir helfen kann.

Das Dilemma vom Anfang an 🎂

JavaScript gibt es schon seit zig Jahren, um genau zu sein seit 1995 (wow, da war ich 8 Jahre alt 😐). Zu der Zeit suchte man Möglichkeiten, wie man Webseiten etwas dynamischer gestalten kann. Anfangs gab es kaum Standards und jeder Browser-Hersteller kochte so seine eigene Suppe. Ältere Entwickler werden noch den Clash zwischen Netscape und Internet Explorer vermutlich noch gut im Hinterkopf haben. Aber JavaScript entwickelte sich immer weiter und wurde auch immer populärer und umfangreicher. Die genaue Geschichte ist aber sehr gut bei Wikipedia belegt. Die ist tatsächlich auch recht interessant und zeigt auch auf, warum viele Java und JavaScript verwechseln beziehungsweise warum es JavaScript heißt.

JavaScript - Wikipedia

Das fundamentale Problem von JavaScript 🏗️

Nun hat JavaScript aber ein fundamentales "Problem". Der Code wird nicht, wie es zum Beispiel bei anderen Programmiersprachen der Fall ist, im Vorfeld kompiliert, sondern lediglich bei der Ausführung (Just-in-Time compilation).

Andere Sprachen können dir im Vorfeld schon sagen, wo es eventuelle Probleme in deinem Code gibt. Das geht bei JavaScript (wenn man vom normalem Standard ausgeht) nicht. Das liegt schlicht und ergreifend daran, dass JavaScript früher in simplen Texteditoren geschrieben wurde und es kaum bis gar keine brauchbare IDE dafür gab. Ich kann mich daran noch sehr gut erinnern, wie man im Notepad an Webseiten nächtelang geschraubt hat und Probleme, die eigentlich offensichtlich waren, schlichtweg einfach nicht gefunden hat.

Genau diese Vorabprüfung fehlt im JavaScript, bis heute und genau hier kommt TypeScript ins Spiel.

Wie genau kann mir denn TypeScript helfen? 🆘

Nun ja, das ist recht einfach. In JavaScript war eine Variable z.B. nicht an einen Datentyp gebunden. Du konntest da einfach alles reinprügeln, problemlos. Der nachfolgende Code soll einfach mal demonstrieren, was mit JavaScript möglich ist und warum es problematisch ist.

var x = 1;

if (x === 1) {
  var x = 2;

  console.log(x);
  // Expected output: 2
}

console.log(x);
// Expected output: 2

Soweit so gut. Klappt auch erst einmal. Nun kommen aber Benutzereingaben ins Spiel oder externe Daten, dann kann es sein, dass xnicht mehr numerisch ist, sondern vielleicht nulloder sogar ein Array.

var x = [1,2,3,4,5]; // not a number anymore

if (x === 1) {
  var x = 2;

  console.log(x);
  // Expected output: 2
}

console.log(x);
// Expected output: 2

Der obige Code würde in dem Falle nicht mal mehr trümmern und aussteigen, sondern er würde prüfen: (x === 1). Da ein Arrayaber nicht 1würde er einfach dann ohne die Anweisungen im ifweiter machen. Noch schlimmer wäre der Code:

// Working code
var str = "Text";

console.log(str.replace("x", "s")) // Expected output: "Test"

// fatal failing code
var str = 1;

console.log(str.replace("x", "s")); // Expected output: Total descruction

Das Resultat wäre, dass das JavaScript eine unbehandelte Exception werfen würde und die weitere Ausführung einfach verweigert. Das Schlimme daran ist aber, dass das nicht nur bei dir zur Entwicklungszeit passiert, sondern auch jedem User der deine Anwendung nutzt. Im Zweifelsfall sieht er nicht einmal was genau das Problem ist, was das Debugging echt schwer macht.

Was genau ist da das Problem? 🤔

Das Problem ist, dass du in JavaScript nicht sicherstellen kannst (außer durch Prüfungen zur Laufzeit, die wiederum mehr Code produzieren würde, den du warten musst und der ggf. auch wieder potenziell Fehler verursachen kann), dass Variablen, Parameter von Methoden etc. nur bestimmte Datentypen annehmen können. Stichwort: Typisierung.

Genau da setzt TypeScript (grundlegend an) und versucht dieses Problem zu lösen, in dem es eine Typisierung auf JavaScript aufsetzt.

TypeScript to the rescue 🛟

TypeScript wurde von Microsoft ca. 2012 von Microsoft ins Leben gerufen um JavaScript-Entwicklern zu helfen, verlässlichen und effizienten Code zu schreiben und orientiert sich da an anderen Sprachen, die Ähnliche Konzepte vorweisen (C# als Beispiel).

Wichtig zu beachten ist aber, dass TypeScript keine eigene Programmiersprache ist. TypeScript ist lediglich eine Obermenge von JavaScript. Das heißt im Kern, dass jeder JavaScript-Code gleichzeitig gültiger TypeScript code ist, umgekehrt jedoch nicht.

Das hat den Vorteil, dass bestehender Code oder Bibliotheken recht schmerzfrei (teil)migriert werden können ohne (zumindest in der Theorie), die generelle Funktionalität zu beeinflussen. TypeScript bietet dabei viele Konzepte, wie man sie auch anderen höheren Sprachen kennt, an. Dazu zählen als Beispiel Typisierung, generische Typen, Interfaces, Typeninferenz und generelle Signaturen von Klassen, Variablen, Methoden etc.

In dem Artikel beschränken wir uns aber lediglich auf den Aspekt der Typisierung.

To compile or not to compile 🎭

TypeScript-Code wird nicht klassisch kompiliert, sondern transpiliert. Das heißt, dass aus unserem TypeScript beim Erzeugen der Anwendung wiederum gültiges JavaScript generiert wird, den die Browser verstehen können. Natives TypeScript können die Browser nämlich nicht. Das sieht man auch schon an den Dateiendungen. TypeScript-Dateien werden mit .tserzeugt und dann zu .jstranspiliert.

Ergo: TypeScript gibt es nur zur Entwicklungszeit.

Typisierung, was zur Hölle? 😈

Sie ist wichtig. Sehr wichtig. Ich selber habe auch jahrelang JavaScript programmiert und habe den Sinn dahinter nicht verstanden, warum man auf einmal JavaScript typisieren sollte. Doch die Vorteile liegen klar auf der Hand, die ich dir gerne mit dem nachfolgendem Code einfach demonstrieren will. Wenn wir uns den JavaScript-Code von oben nehmen und in ein TypeScript-Projekt packen, dann sieht man das recht schnell, dass der Code 1:1 kompatibel ist:

Das Problem ist aber nach wie vor das selbe. Nun kommt aber der Clou. Wir sagen nun, dass ximmer nur numerisch sein darf. Das können wir mit let x: number = 1;machen.

⚠️
Wenn du TypeScript nutzt, solltest du var aus deinem Wortschatz streichen. Var ist böse, weil es nicht angibt, ob die Variable mehrfach beschrieben werden darf (let) oder ob es sich dabei um eine Konstante handelt ( const).

Wenn wir nun x ein Array zuweisen, dann sehen wir was ziemlich cooles:

Unsere Entwicklungsumgebung sagt uns, dass hier etwas nicht stimmt und wir hier schauen müssen. Auch würde das Erstellen/Transpilieren der Anwendung hier abbrechen.

Das selbe Verhalten hätten wir auch mit unserem zweiten Code.

Auch würde er die doppelte Deklaration von var strdirekt monieren:

Was auch vollkommen richtig ist. In JavaScript ging das aber und führte auch da immer wieder zu Problemen.

nuclear explosion GIF

Damit siehst du schon bereits beim Entwickeln, dass du unter Umständen Probleme im Code hast, noch bevor deine Anwendung an den Benutzer geht. Das verschafft dir Sicherheit, Selbstbewusstsein, dass deine Anwendung grundlegend klappt und du kannst dir sicher sein, dass Runtime-Fehler sehr stark minimiert werden.

Was kann/sollte man noch alles typisieren? 🤩

Du kannst aber nicht nur Variablen mit Signaturen ausstatten, sondern auch Klassen, Methoden und sogar eigene Interfaces erstellen, mit dem du sicherstellen kannst, dass die Daten auch so kommen, wie du sie erwartest.

// Method signature
function add(left: number, right: number): number {
	return left + right;
}

// Classes
class Person {
    private name: string;
    private age: number;
    private salary: number;

    constructor(name: string, age: number, salary: number) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    toString(): string {
        return `${this.name} (${this.age}) (${this.salary})`; // As of version 1.4
    }
}

Du kannst auch damit Typen mischen (Union-Types) und so verschiedene Arten der Typen komponieren:

function successor(n: number | bigint): number | bigint {
    return ++n
}

Der Code würde nämlich jetzt für ndie Typen numberoder biginterwarten und diese auch so zurückgeben. Gibt es da Probleme, siehst du es auch.

Was du unbedingt nicht tun solltest! 😖

TypeScript bietet für viele verschiedene Dinge unterschiedliche Typen an.

Documentation - Everyday Types
The language primitives.

Der Typ, den du am besten direkt wieder vergessen solltest, ist any. Any ist praktisch das TypeScript äquivalent zu keiner Typisierung. Damit sagst du TypeScript nur, dass auch dieser Typ alles sein kann und schon hast du die selben Probleme wie in JavaScript, jedoch aber in TypeScript. Genau das sagt auch die Doku von TypeScript:

You usually want to avoid this, though, because any isn’t type-checked. Use the compiler flag noImplicitAny to flag any implicit any as an error.

Prinzipiell wird man auch nie anybenötigen, denn alles (und damit meine ich wirklich alles) lässt sich typisieren. Entweder bieten verwendete Bibliotheken direkt Typen an oder du schreibst sie eben selbst.

Tu dir selbst einen Gefallen und nutze bitte niemals any. Es gibt keinen Grund dafür und wenn du dir unsicher bist, verwende unknown, dafür gibt es den Typ.

Video gif. A cute grey tabby cat sits on her haunches with her paws together as if begging. Text, "Please."

Fazit 🎉

Ich hoffe ich konnte dir damit schon einmal einen kleinen Einblick in TypeScript geben und dir aufzeigen, wie TypeScript dich aktiv dabei unterstützen kann, besseren und zuverlässigeren Code zu schreiben. Ich weiß, dass es am Anfang hinderlich erscheint, aber glaub mir, seit dem ich TypeScript verstanden habe und es aktiv lebe, möchte ich nichts anderes mehr haben.

Im nächsten Artikel über TypeScript möchte ich dir gerne zeigen, wie du mit Interfaces umgehst und wie generische Typen dir helfen, doppelten Code zu vermeiden.