Christoph Haag

Christoph Haag

Christoph ist Softwareentwickler mit einer Passion für Musik

23.11.2022 | 9 min Lesezeit

Parameter implicitly has an any type

Oder: Was ist eigentlich TypeScript?

Parameter implicitly has an any type blog image

JavaScript ist vermutlich die meistgenutzte Programmiersprache weltweit [Link]. Sie ist die Sprache des Webs da sie dynamische Webseiten erst ermöglicht, kommt aber auch in unzähligen Backends durch Node.js zum Einsatz. Sie existiert seit über 25 Jahren und wird noch sehr lange leben.

Doch warum mit einer JavaScript-Hymne beginnen, wenn das Thema dieses Blogs TypeScript sein soll? Ganz einfach: Ohne JavaScript gibt es kein TypeScript.

TypeScript hat am 1. Oktober 2022 sein 10-jähriges (öffentliches) Bestehen gefeiert. Anfänglich durchaus Kontroversen in der JavaScript Community ausgesetzt, gewinnt TypeScript zunehmend an Bedeutung und Beliebtheit. Das ist bei näherem Blick wenig verwunderlich, da genau dies das Ziel von TypeScript ist: Auf den Erfolgen von JavaScript aufbauen und dabei einige der Schwächen eliminieren.

In diesem Blog-Eintrag möchte ich beleuchten was das Wesen von TypeScript ist und dazu motivieren, es öfter in eigenen Projekten zu verwenden.

Was ist Typescript?

Der Blog-Eintrag zum 10-jährigen Jubiläum fasst die Ziele und damit was TypeScript ist und ausmacht sehr gut zusammen:

  • In Kombination mit, bzw. parallel zu JavaScript existieren
  • Es soll sich wie JavaScript verhalten
  • Es soll sich wie JavaScript anfühlen
  • Zur Laufzeit des Programms gibt es nur noch JavaScript

In Summe: "all [goals] really point TypeScript towards simply being a type-checker for JavaScript, adding only syntax that’s necessary for type-checking".

TypeScript in Aktion

Um diese Aussagen zu verdeutlichen, folgen hier ein paar praktische Beispiele. Dafür wird zuerst der TypeScript Compiler installiert.

TypeScript Compiler installieren
> npm i -g typescript
> tsc --version
> Version 4.8.4

Der TypeScript Compiler akzeptiert JavaScript und gibt es 1:1 wieder aus

In diesem Beispiel übergeben wir dem TypeScript Compiler eine einfache JavaScript Datei, welche die Funktion zum Addieren zweier Zahlen bereitstellt. Um das zu ermöglichen benötigen wir das Flag --allowJs und müssen einen Output angeben (--outFile), da unsere Datei sonst überschrieben wird.

> tsc example.js --allowJs --outFile output.js
// example.js
function add(a, b) {
  return a + b;
}

// output.js
function add(a, b) {
  return a + b;
}

Jede Zeile JavaScript ist auch TypeScript

In diesem Beispiel mit dem selben Code von oben, wurde nur die Dateiendung zu .ts geändert. Der TypeScript Compiler benötigt nun keine Flags und erzeugt eine Datei mit dem selben Namen, nur mit .js Endung.

> tsc example.ts
// example.ts
function add(a, b) {
  return a + b;
}

// example.js
function add(a, b) {
return a + b;
}

Keine Fehler. Und das obwohl keinerlei Typen definiert wurden. Standardmäßig ist der Type-Checker optional.

Um die Typenüberprüfung scharf zu schalten gibt es das Flag --strict. Wird dieses aktiviert, erhalten wir folgende Ausgabe beim Kompilieren:

> tsc example.ts --strict
// example.ts
function add(a, b) {
  return a + b;
}

// example.ts:1:14 - error TS7006: Parameter 'a' implicitly has an 'any' type.
// function add(a, b) {
// ~

// example.js
"use strict";
function add(a, b) {
  return a + b;
}

Wir erhalten dennoch eine JavaScript Datei. Das unterstreicht: TypeScript Typen sind vollständig optional. Trotz 'fehlerhaftem' TypeScript-Code wird dennoch gültiges JavaScript erzeugt (wenn es sich um gültiges JavaScript handelt).

Vorteile & Features von TypeScript

Die neuesten Features von JavaScript verwenden

ECMAScript

JavaScript (korrekt wäre ECMAScript, JavaScript ist die Implementierung) wird vom TC39 Komitee spezifiert und weiterentwickelt. Jedes Jahr gibt es eine neue Version der Spezifikation. Aktuell befinden wir uns bei ES2023 (ES ist die Abkürzung für ECMAScript).

Um die neuesten Features des Standards (im Browser) verwenden zu können, müssen die Browserhersteller diese Features erst implementieren. So ist der Standard ES6 (2015) in Googles Chrome erst seit Januar 2017 in Version 58 vollständig unterstützt (siehe w3schools ES6). Das ist der Grund warum es Webseiten wie Can I use gibt, die die Feature-Kompatibiliät mit den verschiedenen Browsern aufzeigen.

Der TypeScript Compiler ermöglicht es, die neusten Features von JavaScript zu verwenden, ohne den Support für Browser aufzugeben, die diese Features noch nicht implementieren. Dies geschieht durch das --target Flag. Im folgenden Beispiel ist zu sehen, dass ES5 das const Schlüsselwort noch nicht unterstützt. Der TypeScript Compiler generiert gültiges JavaScript in der entsprechenden Version.

> tsc example.ts --target <es6|es5>
// example.ts
const p = "hello world";

// example.js (es6)
const p = "hello world";

// example.js (es5)
var p = "hello world";

An dieser Stelle sei angemerkt, dass für das 'Herunterkompilieren' in vielen Projekten Babel verwendet wird.

Developer-Experience

Aus meiner persönlichen Erfahrung der größte, wichtigste und gleichzeitig der am meisten unterschätzte Punkt. Entwickler, die selbstbewusst in dem sind, was sie tun und dabei vom Tooling untersützt werden, werden sowohl zufriedener sein, bessere Arbeit leisten als auch sich stärker mit dem Produkt identifizieren. Dazu trägt zu nicht unerheblichem Teil die Developer-Experience beim Schreiben des Codes bei (siehe z.B. ein Artikel von heise online).

Autovervollständigung

Ein Beispiel in Bildern. Zuerst VS-Code ohne Autovervollständigung, dann mit.

VS-Code ohne Autovervollständigung
VS-Code ohne Autovervollständigung

VS-Code mit Autovervollständigung
VS-Code mit Autovervollständigung

Wahrscheinlich wird sich jeder Entwickler über ein Tooling freuen, das das zweite Bild ermöglicht. Glücklicherweise stellt Visual Studio Code Autovervollständigung in JavaScript automatisch zur Verfügung. Dazu versucht VS-Code zu jedem installierten Paket die Typ-Informationen über das Definitely Typed Projekt transparent im Hintergrund herunterzuladen.

Strg + Leertaste = ❤️

Soll eigener Code das selbe Maß an Unterstützung bieten, kommt man um TypeScript kaum herum.

Code-Dokumentation

Typisierung bedeutet immer auch Dokumentation. Ist ein Parameter einer Funktion ein boolean oder ein string? Ist null oder undefined erlaubt? Was wird zurück gegeben? Welche Properties sind in einem Objekt erlaubt? All das sind Fragen, die mit Typings einfach zu beantworten sind, ohne, dass ein Entwickler die Implementierung der Funktion anschauen muss.

Ein einfachst mögliches Beispiel:

add.js
function add(a, b) { ... }

Was ist das Ergebnis von add('1', '5')? Ist es 6, '15', oder gibt es gar einen Fehler? Ohne die Implementierung anzuschauen ist diese Frage nicht zu beantworten. Wohingegen sich die Frage bei folgender Deklaration erübrigen sollte:

add.js
function add(a: number, b: number): number { ... }

Typen garantieren keine korrekte Implementierung, aber sie helfen zu verstehen, welchen Zweck eine Methode verfolgt.

Types are one of the best forms of documentation you can have. The function signature is a theorem and the function body is the proof. [Link]

Fehler entdecken, bevor sie auftreten

TypeScript hilft dabei typische Fehlerquellen in JavaScript zu vermeiden.

Im Additionsbeispiel von oben:

add.js
add("1", "5");
//  ~~~
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Die Aussage, dass TypeScript und im Allgemeinen typisierte Sprache dazu führen, dass Code weniger Fehler enthält, ist die wahrscheinlich am kontroversesten diskutierte Aussage in der Community in Bezug auf JavaScript vs TypeScript. So gibt es Studien, die zum Schluss kommen: "that strong typing is better than weak typing; that static typing is better than dynamic" [Link] und gleichzeitig gibt es Meinungen, die die Sinnhaftigkeit von typisierten Sprachen in Gänze in Frage stellen [Link]. Beide Seiten haben gute Argumente. Meine persönliche Meinung ist, dass die Frage nach der Korrektheit von Code die Falsche Frage ist, die konkret TypeScript weder beantworten will noch kann. Soll korrekter Code geschrieben werden, muss dies durch Tests validiert werden.

Typische Fehler sind außerdem:

  • Schreibfehler: Variablen-Namen verwenden, die nicht existieren
  • Unwissenheit und/oder 'Leichtsinnsfehler': Methoden aufrufen, die nicht existieren
Gültiges JavaScript
Gültiges JavaScript, das zur Laufzeit fehlschlägt
Ungültiges TypeScript
TypeScript erkennt Fehler, bevor sie auftreten

Skalierung

Das Kernziel bei der Einführung von TypeScript:

Today, we’re introducing a new programming language that solves a very specific problem – getting JavaScript development to scale. [Link]

Es scheint, dass dies ein tatsächliches Problem in der JavaScript-Welt ist. So schreibt beispielsweise Slack: "Managing large JavaScript codebases is challenging". Einem Satz, dem ich mit meiner persönlichen Erfahrung zustimme.

Warum TypeScript hier eine Lösung sein kann? Es ist die logische Konsequenz aus den genannten Punkten von oben: verbesserte Developer Experience, Code, der sich selbst dokumentiert und Fehler, die früher gefunden werden.

Trends & Facts

Zunehmend große Projekte, Teams und Firmen setzen auf TypeScript. Ein paar Beispiele:

Ebenso nimmt die Zahl an in TypeScript geschriebenen Paketen zu. Ein paar nennenswerte Beispiele aus meiner Erfahrung als React-Entwickler:

Erwähnenswert ist außerdem die Entwickler-Umfrage von StackOverflow für das Jahr 2022. Darin ist TypeScript auf Platz 5 der meist genutzten Programmiersprachen, noch vor Java und C#, sowie auf Platz 4 der beliebtesten und am wenigsten gefürchteten Programmiersprachen.

Vorbehalte, Nachteile und Anmerkungen

Es gibt ein paar Dinge, die es Wert sind erwähnt zu werden. Denn auch TypeScript bringt ein paar Komplikationen mit sich:

  • TypeScript ist JavaScript. Wer schlechten JavaScript Code schreibt, wird auch schlechten TypeScript Code schreiben
  • Leicht aufwendigeres Tooling. Es wird mindestens ein Schritt mehr benötigt, um TypeScript in JavaScript zu kompilieren
  • Erhöhter initialer Aufwand beim Aufsetzen eines Projekts. Für vieles gibt es allerdings Templates mit TypeScript Support (z.B. create-react-app)
  • Lernkurve: Ein paar Grundlagen sollten bekannt sein, bevor man durchstartet
  • Komplexität: Es gibt Dinge, die schlichtweg schwierig zu typisieren sind

Fazit

TypeScript vereinfacht das Entwickeln und Warten von JavaScript Projekten. Es hilft Code zu dokumentieren, Fehler früher zu entdecken und Entwickler glücklicher zu machen. Alles Punkte, die ich persönlich nicht mehr missen möchte. Zudem ist die Community groß und es kann einfach in existierende JavaScript Projekte integriert werden. Genug Motivation, um es im aktuellen oder nächsten Projekt selbst einmal auszuprobieren?