Appearance
Kapitel 11: Praxis-Projekte
🎯 Lernziele
In diesem Kapitel lernen Sie:
- ✅ Datenstrukturen mit Interfaces definieren
- ✅ Funktionen mit Generics kapseln
- ✅ Geschäftslogik mit Klassen kapseln
- ✅ Formulardaten mit Typen einschränken
- ✅ Eine vollständige TodoList mit TypeScript erstellen
11.1 Datenstrukturen mit Interfaces definieren
📖 Einfache Definition
Verwenden Sie Interfaces, um Datenstrukturen klar zu definieren.
💻 Code-Beispiel
typescript
// Interfaces für eine Blog-Anwendung
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'author' | 'reader';
createdAt: Date;
}
interface Post {
id: number;
title: string;
content: string;
author: User;
tags: string[];
status: 'draft' | 'published' | 'archived';
createdAt: Date;
updatedAt: Date;
}
interface Comment {
id: number;
postId: number;
author: User;
content: string;
createdAt: Date;
}🎨 Praxis-Beispiel
typescript
// API-Response Typen
interface ApiResponse<T> {
success: boolean;
data: T;
message?: string;
error?: string;
}
// Verwendung
type GetUserResponse = ApiResponse<User>;
type GetPostsResponse = ApiResponse<Post[]>;
type CreatePostResponse = ApiResponse<Post>;11.2 Funktionen mit Generics kapseln
📖 Einfache Definition
Verwenden Sie Generics, um wiederverwendbare Tool-Funktionen zu erstellen.
💻 Code-Beispiel
typescript
// Generische API-Funktion
async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
return response.json();
}
// Verwendung
const userResponse = await fetchApi<User>('https://api.example.com/users/1');
const postsResponse = await fetchApi<Post[]>('https://api.example.com/posts');
console.log(userResponse.data.name);
console.log(postsResponse.data[0].title);🎨 Weitere generische Tool-Funktionen
typescript
// 1. Daten filtern
function filterData<T>(data: T[], predicate: (item: T) => boolean): T[] {
return data.filter(predicate);
}
// 2. Daten sortieren
function sortData<T>(data: T[], compareFn: (a: T, b: T) => number): T[] {
return [...data].sort(compareFn);
}
// 3. Eindeutige Werte extrahieren
function uniqueBy<T, K extends keyof T>(data: T[], key: K): T[] {
const seen = new Set<any>();
return data.filter(item => {
const value = item[key];
if (seen.has(value)) return false;
seen.add(value);
return true;
});
}
// Verwendung
const users: User[] = [/* ... */];
const uniqueEmails = uniqueBy(users, 'email');11.3 Geschäftslogik mit Klassen kapseln
📖 Einfache Definition
Verwenden Sie Klassen, um Geschäftslogik zu kapseln.
💻 Code-Beispiel
typescript
// Service-Klasse für Benutzer-Operationen
class UserService {
private apiUrl: string;
constructor(apiUrl: string) {
this.apiUrl = apiUrl;
}
// Alle Benutzer abrufen
async getAll(): Promise<User[]> {
const response = await fetch(`${this.apiUrl}/users`);
return response.json();
}
// Benutzer nach ID abrufen
async getById(id: number): Promise<User | undefined> {
const response = await fetch(`${this.apiUrl}/users/${id}`);
return response.json();
}
// Benutzer erstellen
async create(user: Omit<User, 'id' | 'createdAt'>): Promise<User> {
const response = await fetch(`${this.apiUrl}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user)
});
return response.json();
}
// Benutzer aktualisieren
async update(id: number, updates: Partial<User>): Promise<User> {
const response = await fetch(`${this.apiUrl}/users/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
return response.json();
}
// Benutzer löschen
async delete(id: number): Promise<void> {
await fetch(`${this.apiUrl}/users/${id}`, {
method: 'DELETE'
});
}
}
// Verwendung
const userService = new UserService('https://api.example.com');
async function main() {
const users = await userService.getAll();
console.log(users);
}11.4 Typen für Formulardaten
📖 Einfache Definition
Verwenden Sie Typen, um Formulardaten zu validieren.
💻 Code-Beispiel
typescript
// Formular-Typen
interface LoginForm {
email: string;
password: string;
rememberMe: boolean;
}
interface RegisterForm {
name: string;
email: string;
password: string;
confirmPassword: string;
agreeToTerms: boolean;
}
// Formular-Validierung
function validateLoginForm(form: LoginForm): string[] {
const errors: string[] = [];
if (!form.email.includes('@')) {
errors.push('Ungültige E-Mail-Adresse');
}
if (form.password.length < 8) {
errors.push('Passwort muss mindestens 8 Zeichen lang sein');
}
return errors;
}
// Verwendung
const loginForm: LoginForm = {
email: 'max@example.com',
password: '12345678',
rememberMe: true
};
const errors = validateLoginForm(loginForm);
if (errors.length > 0) {
console.log('Validierungsfehler:', errors);
}11.5 Praxis: TodoList mit TypeScript
📖 Projekt-Übersicht
Erstellen Sie eine vollständige TodoList-Anwendung mit TypeScript.
Schritt 1: Datenstrukturen definieren
typescript
// src/types/todo.ts
export interface Todo {
id: number;
title: string;
description?: string;
completed: boolean;
priority: 'low' | 'medium' | 'high';
createdAt: Date;
updatedAt: Date;
}
export type CreateTodoDto = Omit<Todo, 'id' | 'createdAt' | 'updatedAt'>;
export type UpdateTodoDto = Partial<CreateTodoDto>;
export interface TodoFilter {
completed?: boolean;
priority?: Todo['priority'];
search?: string;
}Schritt 2: Todo-Service erstellen
typescript
// src/services/TodoService.ts
import type { Todo, CreateTodoDto, UpdateTodoDto, TodoFilter } from '../types/todo';
class TodoService {
private todos: Todo[] = [];
private nextId: number = 1;
// Alle Todos abrufen (mit optionalem Filter)
getAll(filter?: TodoFilter): Todo[] {
let result = [...this.todos];
if (filter) {
if (filter.completed !== undefined) {
result = result.filter(todo => todo.completed === filter.completed);
}
if (filter.priority) {
result = result.filter(todo => todo.priority === filter.priority);
}
if (filter.search) {
const search = filter.search.toLowerCase();
result = result.filter(todo =>
todo.title.toLowerCase().includes(search) ||
(todo.description && todo.description.toLowerCase().includes(search))
);
}
}
return result;
}
// Todo nach ID abrufen
getById(id: number): Todo | undefined {
return this.todos.find(todo => todo.id === id);
}
// Todo erstellen
create(data: CreateTodoDto): Todo {
const now = new Date();
const todo: Todo = {
id: this.nextId++,
title: data.title,
description: data.description,
completed: false,
priority: data.priority || 'medium',
createdAt: now,
updatedAt: now
};
this.todos.push(todo);
return todo;
}
// Todo aktualisieren
update(id: number, updates: UpdateTodoDto): Todo | undefined {
const todo = this.getById(id);
if (!todo) return undefined;
if (updates.title !== undefined) todo.title = updates.title;
if (updates.description !== undefined) todo.description = updates.description;
if (updates.completed !== undefined) todo.completed = updates.completed;
if (updates.priority !== undefined) todo.priority = updates.priority;
todo.updatedAt = new Date();
return todo;
}
// Todo löschen
delete(id: number): boolean {
const index = this.todos.findIndex(todo => todo.id === id);
if (index === -1) return false;
this.todos.splice(index, 1);
return true;
}
// Alle Todos löschen
deleteAll(): void {
this.todos = [];
this.nextId = 1;
}
}
export default TodoService;Schritt 3: Anwendung erstellen
typescript
// src/app.ts
import TodoService from './services/TodoService';
import type { Todo, CreateTodoDto } from './types/todo';
// Service instanziieren
const todoService = new TodoService();
// Beispiel-Verwendung
function main(): void {
console.log('=== TodoList Anwendung ===\n');
// 1. Todos erstellen
const todo1: CreateTodoDto = {
title: 'TypeScript lernen',
description: 'TypeScript Grundlagen verstehen',
priority: 'high'
};
const todo2: CreateTodoDto = {
title: 'Einkaufen gehen',
priority: 'medium'
};
const created1 = todoService.create(todo1);
const created2 = todoService.create(todo2);
console.log('Erstellte Todos:');
console.log(created1);
console.log(created2);
console.log('');
// 2. Alle Todos abrufen
const allTodos = todoService.getAll();
console.log(`Insgesamt ${allTodos.length} Todos\n`);
// 3. Todo aktualisieren
todoService.update(created1.id, { completed: true });
console.log('Todo 1 als erledigt markiert\n');
// 4. Todos filtern
const completedTodos = todoService.getAll({ completed: true });
console.log(`Erledigte Todos: ${completedTodos.length}\n`);
// 5. Todo löschen
todoService.delete(created2.id);
console.log('Todo 2 gelöscht\n');
// 6. Verbleibende Todos anzeigen
const remainingTodos = todoService.getAll();
console.log(`Verbleibende Todos: ${remainingTodos.length}`);
console.log(remainingTodos);
}
main();Schritt 4: Kompilieren und ausführen
bash
# TypeScript kompilieren
tsc
# Anwendung ausführen
node dist/app.jsErwartete Ausgabe:
=== TodoList Anwendung ===
Erstellte Todos:
{ id: 1, title: 'TypeScript lernen', ... }
{ id: 2, title: 'Einkaufen gehen', ... }
Insgesamt 2 Todos
Todo 1 als erledigt markiert
Erledigte Todos: 1
Todo 2 gelöscht
Verbleibende Todos: 1
{ id: 1, title: 'TypeScript lernen', completed: true, ... }📝 Zusammenfassung
In diesem Kapitel haben Sie gelernt:
- ✅ Interfaces für Datenstrukturen verwenden
- ✅ Generics für wiederverwendbare Funktionen
- ✅ Klassen für Geschäftslogik
- ✅ Typen für Formulardaten
- ✅ Praktische TodoList mit TypeScript erstellen
🎯 Nächstes Kapitel
Im Kapitel 12 lernen wir häufig gestellte Interviewfragen zu TypeScript!
👉 Weiter zu Kapitel 12: Interviewfragen
❓ Häufig gestellte Fragen
F: Warum Interfaces statt Type Aliases verwenden?
A: Interfaces sind besser für Objekt-Typen, da sie "Declaration Merging" unterstützen und besser lesbar sind.
F: Wann sollte ich Generics verwenden?
A: Wenn Sie Funktionen oder Klassen schreiben, die mit verschiedenen Typen arbeiten sollen.
F: Ist es notwendig, für jedes Formular Typen zu definieren?
A: Ja! Es hilft, Fehler frühzeitig zu erkennen und bietet bessere IDE-Unterstützung.
🎉 Herzlichen Glückwunsch! Sie haben Kapitel 11 abgeschlossen!
