Einführung
TypeScript ist eine universelle Programmiersprache, die in verschiedenen Entwicklungsumgebungen eingesetzt wird. Seit ihrer Veröffentlichung hat sie sich großer Beliebtheit bei Entwicklern und Unternehmen erfreut, was sich unter anderem darin zeigt, dass sie 2022 auf GitHub zu den vier meistgenutzten Programmiersprachen zählte. Seitdem hat die Bedeutung von TypeScript stetig zugenommen.
Darüber hinaus spiegelt sich die Popularität von TypeScript in der Fülle an Stellenangeboten wider: Über 20.000 Stellen im Zusammenhang mit TypeScript werden auf LinkedIn ausgeschrieben, und große Branchenakteure wie Trivago und Stripe entscheiden sich dafür, ihre Technologie-Stacks auf TypeScript umzustellen.
In diesem Artikel werden wir TypeScript von Grund auf untersuchen, um seine Vorteile zu verstehen, die zu seiner zunehmenden Verwendung in der Entwicklergemeinschaft geführt haben.
TypeScript vs. JavaScript
TypeScript ist nicht völlig neu. Es ist eine Erweiterung von JavaScript, die die Einschränkungen von JavaScript selbst behebt. Als Erweiterung von JavaScript fügt TypeScript statische Typisierung hinzu.
Diese statische Typisierung kann auf zwei gängige Arten deklariert werden:
1. Typannotationen
Dies beinhaltet die sofortige Angabe von Variablen und ihren Datentypen bei ihrer ersten Deklaration. Zum Beispiel so:
let name: string = "HygraphHierbei ist „name“ der Name der Variablen und „string“ ihr Datentyp.
2. Typaliase
Bei dieser Methode wird ein Typ separat mit dem Schlüsselwort „type“ definiert und anschließend zur Annotation von Variablen verwendet.
type StringType = {
name: string;
};
let name: StringType = { name: "Hygraph" };Schauen wir uns nun einige der Funktionen an, die TypeScript bietet.
Die wichtigsten Funktionen von TypeScript
Statische Typisierung
Bei statischer Typisierung werden Variablen zur Kompilierzeit explizit mit ihren Datentypen (z. B. Integer, String, Boolean) deklariert, und das System führt vor der Programmausführung eine Typüberprüfung durch.
Das folgende Verhalten ist in JavaScript zulässig, führt aber in TypeScript aufgrund der TypeScript-Typimplementierung zu einem Fehler.
let name: string = "hygraph";
name = 2000Optionale Typisierung
TypeScript erlaubt zwar die explizite Deklaration von Variablen, unterstützt aber auch das Schreiben von JavaScript-ähnlichem Code ohne Typdeklaration. TypeScript leitet den Typ automatisch ab. Zum Beispiel:
let name = "Hygraph";Im obigen Beispiel schließt TypeScript aus dem Wert der Variableninitialisierung, dass der Typname eine Zeichenkette ist, beispielsweise "Hygraph".
TypeScript-Generics
Durch die Parametrisierung von Typen und Funktionen erzeugen TypeScript-Generics wiederverwendbare Komponenten und Funktionen, die mit verschiedenen Typen arbeiten können, ohne die Typsicherheit zu beeinträchtigen:
// Generic function to return the length of an array
function getArrayLength<T>(array: T[]): number {
return array.length;
}
// Using the generic function with different types of arrays
const stringArray: string[] = ["apple", "banana", "orange"];
const numberArray: number[] = [1, 2, 3, 4, 5];
console.log(getArrayLength(stringArray)); // Output: 3
console.log(getArrayLength(numberArray)); // Output: 5Generics sind im Allgemeinen nützlich, um benutzerdefinierte Datentypen zu definieren, die mit Datentypen wie Bäumen, Graphen und Warteschlangen zusammenarbeiten müssen.
Erweitertes Typsystem
Das TypeScript-Typsystem geht über die grundlegende statische Typisierung hinaus. Es bietet auch Funktionen zum Definieren komplexer Typen, zum Manipulieren von Typen, zum Herstellen von Beziehungen zwischen Variablen, zum Durchsetzen von Typbeschränkungen und andere Möglichkeiten, die eine fehlerfreie Anwendungsentwicklung ermöglichen.
Betrachten wir einige der am häufigsten verwendeten fortgeschrittenen Typen.
1. Arten von Vereinigungen
Union in TypeScript bezeichnet die Deklaration einer Variablen oder eines Funktionsarguments, das mehrere Datentypen enthalten kann. Dies ist hilfreich, wenn ein Wert zur Laufzeit unterschiedliche Datentypen aufweisen kann.
Union-Typen werden durch das Symbol | dargestellt, welches die Datentypen trennt. Zum Beispiel:
let age = number | string;
age = 10;
age = "ten";Wie oben gezeigt, können wir festlegen, dass die Variable „Alter“ zwei Datentypen haben kann. Dies bietet Flexibilität, ohne die Typsicherheit zu beeinträchtigen.
2. Arten von Kreuzungen
Crossovers ermöglichen die Erstellung eines neuen Typs durch die Kombination mehrerer bestehender Typen. Dieser neue Typ besitzt die Eigenschaften und Funktionen der kombinierten Typen.
Schnittmengen werden mithilfe des &-Symbols zwischen den zu kombinierenden Typen erstellt. Zum Beispiel:
interface User {
id: number;
username: string;
email: string;
}
interface Admin {
isAdmin: boolean;
}
// A new type using intersection type
type UserAndAdmin = User & Admin;Hierbei kombiniert der Typ „User AndAdmin“ Funktionen sowohl der Benutzeroberfläche als auch der Administration, um einen Typ zu erzeugen, der alle Funktionen beider Bereiche benötigt.
3. Bedingte Typen
Bedingte Typen in TypeScript erzeugen Typen, die von einem Zustand abhängen. Dies ermöglicht die Definition dynamischer Typen, die sich je nach Eigenschaften, Werten oder Kontext des Typs ändern.
Betrachten wir ein einfaches Beispiel:
// A conditional type to determine if a type is an array
type IsArray<T> = T extends any[] ? true : false;
// Test the conditional type with different types
type Result1 = IsArray<number>; // false
type Result2 = IsArray<string[]>; // true
type Result3 = IsArray<boolean | []>; // trueBedingte Typen werden mithilfe des ternären Operators (? 🙂) in spitzen Klammern (<>) definiert und als “generischer Typparameter” bezeichnet – dazu später mehr. Sie verwenden außerdem das Schlüsselwort `extends`, das prüft, ob ein Typ eine bestimmte Bedingung erfüllt, und basierend auf dem Ergebnis dieser Bedingung einen anderen Typ erzeugt.
4. Arten von Abbildungen
In TypeScript ermöglichen zugeordnete Typen die Erstellung neuer Typen durch Konvertierung von Eigenschaften bestehender Typen. Dies geschieht durch Iteration über die Eigenschaften eines Quelltyps und Anwendung einer Konvertierung auf jede Eigenschaft, um einen neuen Typ zu erzeugen. Zum Beispiel:
// type representing a user
type User = {
id: number;
username: string;
email: string;
};
// Mapped type to make all properties optional
type OptionalUser = { [P in keyof User]?: User[P] };
// New type using the mapped type
const optionalUser: OptionalUser = { id: 1 };
// Property 'email' is now optional
optionalUser.username = "john_doe";
// Property 'id' is still required
// optionalUser.email = "[email protected]"; // Error: Property 'email' is missingZugeordnete Typen werden mithilfe der Syntax { [P in keyof Type]: NewType } definiert, wobei Type der Quelltyp, P der Eigenschaftsschlüssel und NewType der konvertierte Typ ist. P iteriert über die Eigenschaftsschlüssel und definiert die Transformation.
5. Gib den Spitznamen ein.
Typaliase ermöglichen es Ihnen, benutzerdefinierte Namen (Aliase) für bestehende TypeScript-Typen zu erstellen, darunter primitive Datentypen, Union-Typen, Schnittmengentypen und sogar komplexere Typen wie Objektliterale und Funktionstypen. Ein Typalias wird mit dem Schlüsselwort `type` gefolgt vom neuen Namen definiert, wie unten gezeigt:
// type alias for a union type
type Result = "success" | "error";
// type alias for an object literal
type Point = { x: number; y: number };
// type alias for a function type
type Greeting = (name: string) => string;
// Using the type aliases
const status: Result = "success";
const origin: Point = { x: 0, y: 0 };
const greet: Greeting = (name) => Hello, ${name}!;Der obige Code zeigt die verschiedenen Verwendungsmöglichkeiten von Typaliasen für unterschiedliche Typen in TypeScript und deren Verwendung nach der Deklaration.
TypeScript in der objektorientierten Programmierung (OOP)
OOP ist ein Paradigma, das auf dem Konzept von “Objekten” basiert, die miteinander interagieren, um wartbaren und wiederverwendbaren Code zu erzeugen.
1. TypeScript-Klassen
Klassen sind Muster oder Entwürfe zur Erstellung von Objekten, das heißt, sie definieren Daten (Eigenschaften) und Methoden (Funktionen).
Hier ist ein Beispiel für die Implementierung einer Klasse in TypeScript:
class Organization {
private name: string;
private yearFounded: number;
constructor(name: string, yearFounded: number) {
this.name = name;
this.yearFounded = yearFounded;
}
public getDetails(): string {
return `${this.name} was founded in ${this.yearFounded}.`;
}
}
let organization = new Organization("Hygraph", 2015);
console.log(organization.name); // Error: Property 'name' is private and only accessible within class 'Organization'.
console.log(organization.getDetails()); // Output: Hygraph was founded in 2015Im obigen Code haben wir eine Klasse “Organisation” mit privaten Eigenschaften namens „yearFounded“ erstellt, auf die nur innerhalb der Klasse „Organisation“ zugegriffen und die geändert werden können. Beachten Sie die Typisierung der Eigenschaften und Methoden.
2. TypeScript-Schnittstelle
Schnittstellen beschreiben die Struktur von Objekten, indem sie die Eigenschaften und Methoden auflisten, die diese haben müssen, ohne Implementierungsdetails anzugeben:
// Interface representing form data
interface FormData {
firstName: string;
lastName: string;
email: string;
age: number;
}
// Usage
let formData: FormData = {
firstName: "John",
lastName: "Doe",
email: "[email protected]",
age: 30
};Im obigen Beispiel haben wir eine FormData-Schnittstelle definiert, die die Struktur der Formulardaten darstellt.
Als Nächstes erstellten wir ein formData-Objekt mit Eigenschaften, die sich auf die Schnittstellendefinition beziehen.
TypeScript-Nummern
Aufzählungstypen, in TypeScript durch enum dargestellt, sind eine Sammlung benannter Konstanten, die in geschweiften Klammern {} eingeschlossen sind, wobei jeder Konstante ein numerischer oder Zeichenkettenwert zugeordnet ist.
Eine typische TypeScript-Listensammlung könnte folgendermaßen aussehen:
// enum for days of the week
enum DayOfWeek {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
enum HTTPStatusCodes {
OK = 200,
BadRequest = 400,
NotFound = 404,
}Der obige Codeblock erklärt unmittelbar, was geschieht, und demonstriert den semantischen Nutzen der Verwendung von TypeScript-Enumerationen mit Bedeutung.
TypeScript und ES6
TypeScript unterstützt viele Funktionen von ECMAScript 6 (ES6), auch bekannt als ECMAScript 2015. Einige dieser Funktionen sind:
1) Pfeilfunktionen: Im Gegensatz zu herkömmlichen Funktionsausdrücken bieten Pfeilfunktionen eine einfache Syntax zur Definition von Funktionen. Sie ermöglichen die implizite Rückgabe bei einzeiligen Ausdrücken und die automatische Verkettung und eignen sich für Rückruf- oder Ereignisbehandlungsfunktionen.
// Arrow function
const add = (x, y) => x + y;
// Traditional function expression
const add = function(x, y) {
return x + y;
};2) Vorlagenalphabet: Damit lassen sich mehrzeilige Ausdrücke und Zeichenketten direkt im Code in geschweiften Klammern (“) einbetten. Dies vereinfacht die Erstellung dynamischer Zeichenketten, einschließlich interpolierender Variablen und Ausdrücke.
const name: string = "John";
const greeting: string = `Hello, ${name}!`;ES6 bietet noch weitere Funktionen, die in diesem Artikel nicht behandelt werden können. Weitere Informationen finden Sie bei Ecma International.
Vorteile von TypeScript gegenüber JavaScript
Seit der Veröffentlichung von TypeScript vor über einem Jahrzehnt gibt es eine anhaltende Debatte über seine Vorteile gegenüber JavaScript.
In diesem Abschnitt werden wir einige dieser Vorteile genauer betrachten.
- Sicherheitstyp: Das statische Typsystem von TypeScript wendet Typannotationen auf Variablen, Funktionen und Objekte an, was die frühzeitige Fehlererkennung erleichtert und die Wartbarkeit durch Schnittstellen, Klassen und Module verbessert.
- Bessere Entwicklererfahrung: Entwickler können nun mit größerem Vertrauen Code schreiben, da der Compiler potenzielle Typkonflikte erkennt, bevor der Code zur Laufzeit ausgeführt wird. Dies ist besonders hilfreich bei der Migration einer JavaScript-Codebasis zu TypeScript.
Wann sollte man TypeScript verwenden?
Aus den oben genannten Vor- und Nachteilen lässt sich schließen, dass TypeScript möglicherweise nicht für alle Projekte geeignet ist. Das mag stimmen, aber warum sollten Sie diese Entscheidung Ihnen überlassen? Wir helfen Ihnen gern, eine bessere Entscheidung zu treffen.
Wann ist der Einsatz von TypeScript angebracht?
- Großflächige Anwendungen: TypeScript wurde entwickelt, um die Skalierungsprobleme großer JavaScript-Codebasen zu lösen. Mit zunehmender Projektgröße trägt die statische Typisierung dazu bei, Fehler frühzeitig zu erkennen und so die Wartbarkeit des Codes sowie die Zusammenarbeit im Team zu verbessern.
- Teamarbeit: In einem Teamumfeld, in dem mehrere Entwickler zu einer Codebasis beitragen, kann TypeScript die Zusammenarbeit erleichtern, indem es Codierungskonventionen durchsetzt und durch selbstdokumentierenden Code eine bessere Kommunikation ermöglicht.
- Langfristige Projekte: Die Wartung ist die letzte Phase des Softwareentwicklungszyklus und kann ein Jahrzehnt oder auch nur ein Jahr dauern. TypeScript eignet sich für langfristige Projekte, bei denen Wartbarkeit, Skalierbarkeit und Zukunftssicherheit des Codes entscheidende Faktoren sind.
Wann man TypeScript nicht verwenden sollte
Leider ist TypeScript trotz seiner Vorteile möglicherweise nicht für alle Anwendungsfälle geeignet. Zum Beispiel:
- Einfache Projekte: Bei kleinen Projekten mit minimaler Komplexität überwiegen die Vorteile der statischen Typisierung und der fortgeschrittenen Werkzeuge möglicherweise nicht den Konfigurations- und Lernaufwand, der mit TypeScript verbunden ist.
- Alte Codebasen: Die Umstellung großer, bestehender JavaScript-Codebasen auf TypeScript kann eine gewaltige Herausforderung sein. In solchen Fällen rechtfertigt der Aufwand für die Migration zu TypeScript möglicherweise nicht die Vorteile, insbesondere wenn sich das Projekt dem Ende seines Lebenszyklus nähert oder nur noch minimal gewartet wird.









