| Typ | Konzept |
|---|---|
| Quellen | Quelle - Angular Mastery Workshop |
| Erstellt | 2026-09-26 |
| Aktualisiert | 2026-09-26 |
| Tags | typescript, javascript, programmiersprache, webentwicklung |
JavaScript mit Typen: eine Obermenge von JavaScript, in der man nach und nach optionale statische Typen ergänzen kann. Der Compiler findet damit Fehler vor der Ausführung, und Editoren können besser vervollständigen und umbauen. TypeScript ist die Sprache von Angular.
Alle Code-Beispiele stammen aus Quelle - Angular Mastery Workshop (Folie 121–146), von den Folienbildern abgeschrieben.
Grundidee
Jedes gültige JavaScript ist auch gültiges TypeScript. Typen sind optional und lassen sich schrittweise einführen. Wie streng der Compiler prüft, ist einstellbar. TypeScript wird zu JavaScript übersetzt, im Browser läuft also weiterhin JavaScript (Folie 121). Laut Kurs ist TypeScript für ernsthafte Frontend-Projekte zur Standardsprache geworden, die meisten Bibliotheken liefern Typdefinitionen mit (Folie 26).
Grundtypen
const isAmazing: boolean = true;
const kittenCount: number = 7; // number ist eine Gleitkommazahl: Vorsicht bei Divisionen
const language: string = 'typescript'; // Template-Strings: `age: ${age}`
const languages: string[] = ['javascript', 'typescript']; // string[] statt Array<string>
const complex: object = { color: 'orange' }; // alles, was nicht primitiv ist; selten sinnvoll
const whoKnows: any = 'we can assign ANYthing!'; // möglichst vermeiden
(Folie 122–127)
Typinferenz: Der Typ wird aus dem Wert abgeleitet und muss nicht hingeschrieben werden. Nur wo später etwas anderes zugewiesen werden soll, schreibt man den Typ hin, damit er nicht zu eng abgeleitet wird (Folie 128):
const isAmazing = true;
const kittenCount = 7;
const language = 'typescript';
const languages = ['javascript', 'typescript'];
let complex: object = { color: 'orange' }; // let: darf neu zugewiesen werden
let whoKnows: any = 'we can assign ANYthing!';
„Negative“ Typen
let somethingSpecial; // implizit undefined
let somethingEvenMoreSpecial = undefined; // dasselbe, explizit
somethingSpecial === somethingEvenMoreSpecial; // true (strikt gleich, ohne Typumwandlung)
const something = null; // null ist ein echter Wert
something !== somethingSpecial; // true: null ist nicht dasselbe wie undefined
showNotification(notification: Notification): void {
// show notification ... // void: gibt keinen Wert zurück
}
boom(): never {
throw new Error('This is unfortunate...'); // never: endet nie normal
}
(Folie 129–135)
Tipp: null bleibt beim Umwandeln in JSON erhalten, Eigenschaften mit undefined fallen weg. Das ist wichtig, wenn Objekte ans Backend, in die URL oder in den Local Storage gehen (Folie 132).
Interfaces und Typ-Aliase
Interfaces verwendet man für Datenstrukturen wie API-Antworten, Zustand oder Entitäten, nicht Klassen. Interfaces lassen sich verschachteln, ? markiert optionale Felder (Folie 137):
export interface Customer {
id: string;
name: string;
middleName?: string; // optional
surname: string;
address: Address; // Interfaces kombinieren
}
export interface Address {
street: string;
number: string;
zip: number;
city: string;
country: string;
}
Laut offizieller TypeScript-Dokumentation lieber ein Interface als einen Typ-Alias verwenden, ausser bei Vereinigungstypen (A | B) und Tupeln (Folie 136).
Angular bringt eigene Interfaces mit. Passt ein Objekt nicht dazu, meldet der Compiler einen Fehler (Folie 138):
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [ // Routes ist dasselbe wie Route[]
{
path: '',
redirectTo: 'home',
invalid: '' // Fehler!
}
];
// TS2322: Type '{ path: string; redirectTo: string; invalid: string; }' is not assignable to type 'Route'.
// Object literal may only specify known properties, and 'invalid' does not exist in type 'Route'.
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Generics
Generics machen Typen flexibel, ohne die Sicherheit zu verlieren, die man mit any aufgeben würde (Folie 139):
export const customers: Observable<Customer[]>; // RxJS-Strom von Customer-Arrays
httpClient.post<CreateCustomerResponse>(API_URL, newCustomerPayload);
// post liefert ein Objekt vom Typ CreateCustomerResponse
Utility Types
Das sind eingebaute generische Typen, die bestehende Interfaces umformen: Partial, Readonly, Record, Pick, Omit usw. (Folie 140):
function updateCustomer(customer: Customer, update: Partial<Customer>) {
return { ...customer, ...update };
}
export interface Customer {
id: string;
name: string;
middleName?: string;
surname: string;
}
// Partial<Customer> wirkt, als hätte man geschrieben:
export interface PartialCustomer {
id?: string;
name?: string;
middleName?: string;
surname?: string;
}
Praxistipps
public weglassen, weil es der Standard ist. Das spart Code, und private fällt besser auf (Folie 141):
@Injectable({
providedIn: 'root'
})
export class SomeService {
doSomething() { // statt: public doSomething()
// ...
}
private doSomethingElse() {
// ...
}
}
Kurzschreibweise für Konstruktor-Parameter (Folie 142). Die Langform deklariert die Felder und weist sie im Konstruktor zu:
@Injectable({
providedIn: 'root'
})
export class UserService {
private userBackendService: UserBackendService;
private usernameService: UsernameService;
constructor(
userBackendService: UserBackendService,
usernameService: UsernameService
) {
this.userBackendService = userBackendService;
this.usernameService = usernameService;
}
}
Die Kurzform macht dasselbe:
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(
private userBackendService: UserBackendService,
private usernameService: UsernameService
) {}
}
Typinferenz nutzen. Weil die Services ihre Rückgabetypen angeben, braucht es in der Kette keine Typen mehr (Folie 143):
// vorher: explizit typisierte Parameter
this.results$ = this.searchForm.valueChanges
.pipe(
map((formSearchCriteria: FormSearchCriteria) => this.transformer(formSearchCriteria)),
switchMap((searchCriteria: SearchCriteria) => this.searchService.search(searchCriteria)),
map((results: SearchResults) => results.list)
);
// nachher: gleiche Typsicherheit dank Inferenz
this.results$ = this.searchForm.valueChanges
.pipe(
map(formSearchCriteria => this.transformer(formSearchCriteria)),
switchMap(searchCriteria => this.searchService.search(searchCriteria)),
map(results => results.list)
);
Optional Chaining (Folie 144–145):
// unleserlich
let x = foo === null || foo === undefined ? undefined : foo.bar.baz();
// gleichwertig
let x = foo?.bar.baz();
// vorher
if (foo && foo.bar && foo.bar.baz) {
// ...
}
// nachher („After-ish“, weil && auch bei 0 oder '' abbricht, ?. nur bei null/undefined)
if (foo?.bar?.baz) {
// ...
}
Imports gruppieren, damit man auf einen Blick sieht, was eine Komponente benutzt. Das Werkzeug „Import-Conductor“ kann sie automatisch ordnen (Folie 146). Auf der Folie ist der Anfang der Zeilen durch das Logo verdeckt, die Ergänzungen in […] stammen von Claude:
// 1. Fremde Bibliotheken
import { [C]omponent, Input } from '@angular/core';
import { [Obse]rvable } from 'rxjs';
import { […]h, debounceTime } from 'rxjs/operators'; // vermutlich switchMap
// 2. Bibliotheken der eigenen Organisation
import { […], SomeInterface } from '@my-org/some-library';
// 3. Lokale Core- und Shared-Imports
import { […] } from '../../core/auth/auth.service';
import { […] } from '../../core/user/user.service';
import { […]Component } from '../../shared/dialog/confirm-dialog.component';
// 4. Lokale Imports aus dem eigenen lazy Feature
import { CustomerService } from './services/customer.service';
import { Customer } from './customer.interface';
Nie aus einem benachbarten lazy geladenen Feature importieren (siehe Angular-Architektur).
Statische Typen verschieben Fehler von der Laufzeit in die Übersetzungszeit: Was der Compiler prüft, muss kein Test mehr abdecken (siehe Softwaretest). Laut Quelle - Recherche - Angular heute 2026 verlangt Angular 22 inzwischen TypeScript 6 und prüft Templates standardmässig streng (strictTemplates).
Verwandt
- Modernes JavaScript – die Sprache, auf der TypeScript aufbaut
- Angular – setzt TypeScript voraus
- Dependency Injection – nutzt Typen als Schlüssel für die Injektion
