TypeScript erweitert JavaScript um statische Typisierung und objektorientierte Features, die den Entwicklungsprozess robuster und effizienter gestalten. Als Superset von JavaScript bietet TypeScript fortschrittliche Werkzeuge für Fehlerprüfung zur Kompilierungszeit, verbesserte IDE-Unterstützung und umfassende Dokumentationsmöglichkeiten. Diese Grundlagen-Einführung behandelt die wesentlichen Konzepte, Syntax und Vorteile der typsicheren Entwicklung mit TypeScript.

Entstehung und Philosophie

TypeScript wurde 2012 von Microsoft veröffentlicht, um ein fundamentales Problem von JavaScript zu lösen: Das Fehlen eines statischen Typsystems. JavaScript wurde ursprünglich für kleine Scripte in Webseiten entwickelt, wird heute aber für komplexe Anwendungen mit Millionen von Codezeilen verwendet. Diese Evolution brachte Herausforderungen mit sich:

  • Laufzeitfehler: Typfehler werden erst entdeckt, wenn der Code ausgeführt wird.
  • Schlechte Tooling-Unterstützung: IDEs können ohne Typinformationen nur begrenzt helfen.
  • Schwierige Refactorings: Große Codeänderungen sind riskant ohne Compiler-Unterstützung.
  • Unklare APIs: Funktionssignaturen geben keine Hinweise auf erwartete Datentypen.

TypeScript löst diese Probleme durch ein optionales, graduelles Typsystem.

Das bedeutet:

  • Optional: Man kan TypeScript schrittweise einführen. Nicht jede Variable muss typisiert werden.
  • Graduell: Man kann mit JavaScript beginnen und nach und nach Typen hinzufügen.
  • Strukturell: TypeScript verwendet “Duck Typing” - wenn es wie eine Ente aussieht und quakt, ist es eine Ente.

Funktionsweise

TypeScript ist technisch gesehen ein Transpiler (Source-to-Source Compiler). Der TypeScript-Code wird in JavaScript kompiliert, das dann in jedem JavaScript-Runtime läuft.

  1. TypeScript Code (.ts)
  2. TypeScript Compiler (tsc)
  3. JavaScript Code (.js)
  4. JavaScript Runtime

Wichtige Konzepte

Compile-Time vs. Runtime

  • TypeScript existiert nur zur Compile-Zeit
  • Alle Typ-Informationen werden beim Kompilieren entfernt (“Type Erasure”)
  • Der resultierende JavaScript-Code enthält keine Typ-Informationen
  • Typen haben keinen Einfluß auf die Laufzeit-Performance

Superset-Prinzip

  • Jeder gültige JavaScript-Code ist auch gültiger TypeScript-Code
  • TypeScript fügt JavaScript neue Syntax hinzu, ändert aber nicht die Semantik
  • Man kann .js Dateien einfach in .ts umbenennen als Startpunkt

Strukturelle Typisierung

TypeScript Beispiel
// TypeScript kümmert sich um die
// Struktur, nicht um Namen
interface Point {
    x: number;
    y: number;
}

// Diese Klasse implementiert Point
// implizit durch ihre Struktur
class Coordinate {
    constructor(
        public x: number,
        public y: number
    ) {}
}

function printPoint(p: Point) {
    console.log(`(${p.x}, ${p.y})`);
}

// Funktioniert, obwohl Coordinate Point
// nicht explizit implementiert wurde
printPoint(new Coordinate(10, 20));

Vorteile von TypeScript

Früherkennung von Fehlern

In JavaScript werden viele Fehler erst zur Laufzeit entdeckt.

Im folgenden JavaScript-Beispiel wird der Fehler erst bei der Ausführung wirklich sichtbar.

TypeScript Beispiel - JavaScript
function calculatePrice(price, quantity) {
    return price * quantity;
}

calculatePrice("Art-Name", 3);

Hier würde man als Ergebnis ein NaN erhalten. Allerdings erst, wenn man dieses Script ausführen würde.

TypeScript erkennt solche Fehler während der Entwicklung. Hier wurden die Typen für die Parameter hinzugefügt. Somit weiß nun die IDE, dass price nur vom Typ number (Zahl) sein kann.

TypeScript Beispiel - TypeScript
function calculatePrice(price: number, quantity: number) {
    return price * quantity;
}

calculatePrice("Art-Name", 3); // Das Argument vom Typ "string" kann dem Parameter vom Typ "number" nicht zugewiesen werden.

Verbesserte IDE-Unterstützung

TypeScript ermöglicht IDEs, intelligente Features anzubieten:

  • Autocompletion: Die IDE erkennt alle verfügbaren Properties und Methoden
  • Refactoring: Sichere Umbenennungen über die gesamte Codebase
  • Navigation: Man kann zur Definition springen und alle Referenzen finden
  • Inline-Dokumentation: Typ-Informationen als Dokumentation

Selbstdokumentierender Code

Typen fungieren als lebende Dokumentation.

TypeScript Beispiel - Ohne Typen
function processUser(user, options) {
    // ...
}

Hier ist nicht klar, was diese Funktion erwartet.

Mit Typen sind die Erwartungen klar.

TypeScript Beispiel - Mit Typen
interface User {
    id: string;
    name: string;
    email: string;
}

interface ProcessOptions {
    sendEmail?: boolean;
    updateLastLogin?: boolean;
}

function processUser(user: User, options: ProcessOptions): void {
    // ...
}

Refactoring-Unterstützung

Bei großen Codebasen ist Refactoring in JavaScript riskant. TypeScript macht es einfacher.

TypeScript Beispiel
// Änderung einer Property
interface Product {
    id: string;
    // name: string;
    title: string;
    price: number;
}

// TypeScript zeigt Fehler an allen Stellen,
// die noch 'name' verwenden

Installation und Setup

TypeScript kann auf verschiedene Arten verwendet werden.

Globale Installation

Um TypeScript global auf dem System zu installieren, wird NodeJS und NPM benötigt.

npm install -g typescript

Projekt-Setup

Neues Projekt mit TypeScript initialisieren.

mkdir my_project
cd my_project
npm init -y

Anschließend TypeScript als Entwicklungsabhängigkeit installieren. Da TypeScript zu JavaScript kompiliert wird, wird das Paket “TypeScript” nur während der Entwicklung benötigt.

npm install --save-dev typescript

TypeScript-Konfiguration erstellen

npx tsc --init

Grundlegende Konfiguration

Die Konfiguration für TypeScript wird in der Regel in einer tsconfig.json festgehalten. Die tsconfig.json ist das Herzstück jedes TypeScript-Projekts.

Diese Datei (Konfiguration) definiert:

  • Welche Dateien kompiliert werden sollen
  • Welche Compiler-Optionen verwendet werden
  • Wie strikt die Typ-Prüfung sein soll

Hier eine grundlegende Beispiel-Konfiguration.

TypeScript tsconfig.json
{
    "compilerOptions": {
        "target": "es2020",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "outDir": "./dist",
        "rootDir": "./src"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "dist"]
}

Die einzelnen Optionen werden in einem separaten Artikel erklärt.

TypeScript vs. JavaScript - Praktischer Vergleich

Betrachten wir ein realistisches Beispiel - eine Funktion zur Verarbeitung von Benutzerdaten.

TypeScript JavaScript-Version
function processUserData(users, options) {
    if (!options.includeInactive) {
        users = users.filter(u => u.active);
    }

    return users.map(user => {
        id: user.id,
        displayName: options.useFullname
            ? `${user.firstName} ${user.lastName}`
            : user.firstName,
        email: user.email.toLowerCase(),
        lastLogin: new Date(user.lastLogin)
    });
}
TypeScript TypeScript-Version
interface User {
    id: string;
    firstName: string;
    lastName: string;
    email: string;
    active: boolean;
    lastLogin: string | Date;
}

interface ProcessOptions {
    includeInactive?: boolean;
    useFullName?: boolean;
}

interface ProcessedUser {
    id: string;
    displayName: string;
    email: string;
    lastLogin: Date;
}

function processUserData(users: User[], options: ProcessOptions): ProcessedUser[] {
    let filteredUsers = users;

    if (!options.includeInactive) {
        filteredUsers = users.filter(u => u.active);
    }

    return filteredUsers.map(user => {
        id: user.id,
        displayName: options.useFullName
            ? `${user.firstName} ${user.lastName}`
            : user.firstName,
        email: user.email.toLowerCase(),
        lastLogin: user.lastLogin instanceof Date
            ? user.lastLogin
            : new Date(user.lastLogin)
    });
}

Die TypeScript-Version bietet:

  • Klare Dokumentation der erwarteten Datenstrukturen
  • Compile-Zeit-Validierung aller Zugriffe
  • Autocompletion für alle Properties
  • Sichere Refactorings
/ Weiter

Zurück zu TypeScript

Zur Übersicht