Skip to content

Kapitel 13: Häufige Fehler und Fehlerbehebung

🎯 Lernziele

In diesem Kapitel lernen Sie:

  • ✅ Typenkonflikte beheben
  • ✅ Fehlende Eigenschaften beheben
  • ✅ Funktionsparameter-Fehler beheben
  • ✅ Typableitung fehlschlägt
  • any Missbrauch vermeiden
  • ✅ Kompilierungsfehler beheben

13.1 Typenkonflikte

❌ Fehler

typescript
let age: number = "25";  // ❌ Fehler: Type 'string' is not assignable to type 'number'

✅ Lösung

typescript
// Lösung 1: Richtigen Typ verwenden
let age: number = 25;

// Lösung 2: Typ konvertieren
let ageString: string = "25";
let ageNumber: number = Number(ageString);

// Lösung 3: Union Type verwenden (wenn beide Typen erlaubt sind)
let age: string | number = "25";
age = 25;  // ✅ Erlaubt

🎨 Praxis-Beispiel

typescript
// ❌ Falsch: API gibt string zurück, Sie erwarten number
function getUserId(): string {
  return "123";
}

let userId: number = getUserId();  // ❌ Fehler!

// ✅ Richtig: Typ anpassen
let userId: string = getUserId();

// Oder: Konvertieren
let userIdNumber: number = Number(getUserId());

13.2 Fehlende Eigenschaften

❌ Fehler

typescript
interface User {
  id: number;
  name: string;
  email: string;
}

// ❌ Fehler: Property 'email' is missing
const user: User = {
  id: 1,
  name: "Max"
};

✅ Lösung

typescript
// Lösung 1: Alle erforderlichen Eigenschaften hinzufügen
const user: User = {
  id: 1,
  name: "Max",
  email: "max@example.com"  // ✅ Hinzugefügt
};

// Lösung 2: Optionale Eigenschaften verwenden
interface User {
  id: number;
  name: string;
  email?: string;  // Optional
}

const user: User = {
  id: 1,
  name: "Max"
};  // ✅ Erlaubt

🎨 Praxis-Beispiel

typescript
// ❌ Falsch: API-Response könnte fehlende Eigenschaften haben
interface ApiResponse {
  success: boolean;
  data: any;
  message: string;
}

// Backend gibt manchmal kein 'message' zurück
const response: ApiResponse = {
  success: true,
  data: { ... }
};  // ❌ Fehler!

// ✅ Richtig: 'message' optional machen
interface ApiResponse {
  success: boolean;
  data: any;
  message?: string;  // Optional
}

13.3 Funktionsparameter-Fehler

❌ Fehler

typescript
function greet(name: string, age: number): string {
  return `Hallo ${name}, du bist ${age} Jahre alt!`;
}

// ❌ Fehler: Zu wenig Argumente
greet("Max");

// ❌ Fehler: Falscher Typ
greet("Max", "25");

✅ Lösung

typescript
// Lösung 1: Richtige Anzahl und Typen von Argumenten verwenden
greet("Max", 25);  // ✅ Richtig

// Lösung 2: Optionale Parameter verwenden
function greet(name: string, age?: number): string {
  if (age !== undefined) {
    return `Hallo ${name}, du bist ${age} Jahre alt!`;
  }
  return `Hallo ${name}!`;
}

greet("Max");        // ✅ Erlaubt
greet("Max", 25);  // ✅ Erlaubt

// Lösung 3: Standardparameter verwenden
function greet(name: string, age: number = 0): string {
  return `Hallo ${name}, du bist ${age} Jahre alt!`;
}

greet("Max");      // ✅ age = 0
greet("Max", 25);  // ✅ age = 25

🎨 Praxis-Beispiel

typescript
// ❌ Falsch: Zu strenge Typen
function createUser(name: string, age: number, email: string): User {
  return { name, age, email };
}

// Was, wenn ich kein Alter habe?
const user = createUser("Max", ???, "max@example.com");  // ❌ Problem!

// ✅ Richtig: Optionale Parameter
function createUser(name: string, email: string, age?: number): User {
  return { name, age, email };
}

const user1 = createUser("Max", "max@example.com");
const user2 = createUser("Max", "max@example.com", 25);

13.4 Typableitung fehlschlägt

❌ Fehler

typescript
// TypeScript kann den Typ nicht ableiten
let data;  // Typ: any (wenn "noImplicitAny" nicht aktiviert)
data = "Hallo";
console.log(data.toUpperCase());  // ✅ OK, aber keine Typsicherheit!

data = 123;
console.log(data.toUpperCase());  // ❌ Laufzeitfehler! (Aber keine Kompilierungsfehler)

✅ Lösung

typescript
// Lösung 1: Explizite Typen angeben
let data: string;
data = "Hallo";
console.log(data.toUpperCase());  // ✅ OK

data = 123;  // ❌ Fehler: Type 'number' is not assignable to type 'string'

// Lösung 2: Typableitung aktivieren (empfohlen!)
// In tsconfig.json:
{
  "compilerOptions": {
    "noImplicitAny": true  // Erzwingt explizite Typen
  }
}

// Jetzt muss man Typen angeben:
let data: any;  // Explizit (aber besser: spezifischen Typ verwenden)

🎨 Praxis-Beispiel

typescript
// ❌ Falsch: Keine Typen angegeben
function processValue(value) {  // Typ: any
  console.log(value.length);  // Keine Fehlermeldung, aber gefährlich!
}

processValue("Hallo");  // OK
processValue([1, 2, 3]);  // OK
processValue(123);  // ❌ Laufzeitfehler!

// ✅ Richtig: Explizite Typen
function processValue(value: string | any[]): void {
  console.log(value.length);  // Sicher!
}

processValue("Hallo");  // ✅ OK
processValue([1, 2, 3]);  // ✅ OK
processValue(123);  // ❌ Fehler!

13.5 any Missbrauch vermeiden

❌ Fehler

typescript
// ❌ Schlecht: any verwenden (verliert alle Vorteile von TypeScript)
function processData(data: any): any {
  return data.someProperty.anotherProperty;  // Keine Typprüfung!
}

const result = processData({ ... });
console.log(result.foo.bar);  // Keine Fehlermeldung, aber gefährlich!

✅ Lösung

typescript
// Lösung 1: Spezifischen Typ verwenden
interface Data {
  someProperty: {
    anotherProperty: string;
  };
}

function processData(data: Data): string {
  return data.someProperty.anotherProperty;
}

// Lösung 2: unknown verwenden (sicherer als any)
function processData(data: unknown): void {
  if (typeof data === "object" && data !== null) {
    const obj = data as any;  // Type Assertion (vorsichtig!)
    console.log(obj.someProperty);
  }
}

// Lösung 3: Generics verwenden (für wiederverwendbare Funktionen)
function processData<T>(data: T): T {
  return data;
}

🎨 Praxis-Beispiel

typescript
// ❌ Falsch: API-Antwort mit any
async function fetchUser(): Promise<any> {
  const response = await fetch("https://api.example.com/user");
  return response.json();
}

const user = await fetchUser();
console.log(user.name);  // Keine Autovervollständigung!

// ✅ Richtig: API-Antwort mit Interface
interface User {
  id: number;
  name: string;
  email: string;
}

async function fetchUser(): Promise<User> {
  const response = await fetch("https://api.example.com/user");
  return response.json();
}

const user = await fetchUser();
console.log(user.name);  // ✅ Autovervollständigung!

13.6 Kompilierungsfehler beheben

❌ Häufige Fehler

1. "Cannot find module 'xxx'"

typescript
// ❌ Fehler: Cannot find module 'express'
import express from 'express';

Lösung:

bash
# Typdefinitionen installieren
npm install --save-dev @types/express

2. "Property 'xxx' does not exist on type 'yyy'"

typescript
interface User {
  name: string;
}

const user: User = { name: "Max" };
console.log(user.age);  // ❌ Fehler: Property 'age' does not exist on type 'User'

Lösung:

typescript
// Lösung 1: Eigenschaft hinzufügen
interface User {
  name: string;
  age: number;  // ✅ Hinzugefügt
}

// Lösung 2: Optionale Eigenschaft
interface User {
  name: string;
  age?: number;  // ✅ Optional
}

// Lösung 3: Index Signature (wenn dynamische Eigenschaften erlaubt sind)
interface User {
  name: string;
  [key: string]: any;  // ✅ Erlaubt zusätzliche Eigenschaften
}

3. "Type 'xxx' is not assignable to type 'yyy'"

typescript
let age: number = "25";  // ❌ Fehler: Type 'string' is not assignable to type 'number'

Lösung:

typescript
// Typ konvertieren
let age: number = Number("25");  // ✅OK

// Oder: Union Type verwenden
let age: string | number = "25";
age = 25;  // ✅ Erlaubt

4. "Object is possibly 'null' or 'undefined'"

typescript
function getElement(id: string): HTMLElement | null {
  return document.getElementById(id);
}

const element = getElement("myDiv");
element.innerHTML = "Hallo";  // ❌ Fehler: Object is possibly 'null'

Lösung:

typescript
// Lösung 1: Null-Prüfung
const element = getElement("myDiv");
if (element !== null) {
  element.innerHTML = "Hallo";  // ✅ Sicher
}

// Lösung 2: Optional Chaining
const element = getElement("myDiv");
element?.innerHTML = "Hallo";  // ✅ Sicher (macht aber nichts, wenn null)

// Lösung 3: Non-Null Assertion (vorsichtig!)
const element = getElement("myDiv")!;
element.innerHTML = "Hallo";  // ✅ OK (aber gefährlich, wenn wirklich null)

13.7 tsconfig.json Fehler beheben

❌ Häufige Fehler

1. "Cannot write file 'xxx' because it would overwrite input file"

Ursache: outDir und rootDir zeigen auf dasselbe Verzeichnis.

Lösung:

json
{
  "compilerOptions": {
    "rootDir": "./src",    // Quelldateien
    "outDir": "./dist"      // Kompilierte Dateien (müssen unterschiedlich sein!)
  }
}

2. "Include paths must not refer to files or folders outside the baseUrl"

Ursache: Falsche Pfadangaben in tsconfig.json.

Lösung:

json
{
  "compilerOptions": {
    "baseUrl": ".",  // Basisverzeichnis
    "paths": {
      "@/*": ["src/*"]  // Korrekte Pfadangabe
    }
  }
}

13.8 Praxis: Fehlerbehebung in einem Projekt

💻 Vollständiges Beispiel

typescript
// ❌ Code mit Fehlern

// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b): number {  // ❌ Parameter 'b' hat implizit den Typ 'any'
  return a - b;
}

// main.ts
import { add, subtract } from './math';

const result1 = add(5, "3");  // ❌ Fehler: Argument 2 hat den Typ 'string'
const result2 = subtract(5, 3);

console.log(result1);
console.log(result2);

// ✅ Behobener Code

// math.ts
export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b: number): number {  // ✅ Typ hinzugefügt
  return a - b;
}

// main.ts
import { add, subtract } from './math';

const result1 = add(5, 3);  // ✅ Richtig
const result2 = subtract(5, 3);

console.log(result1);  // Ausgabe: 8
console.log(result2);  // Ausgabe: 2

📝 Zusammenfassung

In diesem Kapitel haben Sie gelernt:

  • Typenkonflikte beheben (Typen anpassen, konvertieren, Union Types verwenden)
  • Fehlende Eigenschaften beheben (alle Eigenschaften hinzufügen oder optional machen)
  • Funktionsparameter-Fehler beheben (optionale Parameter, Standardparameter)
  • Typableitung aktivieren (noImplicitAny)
  • any Missbrauch vermeiden (spezifische Typen, unknown, Generics)
  • Kompilierungsfehler beheben (Modulfehler, Eigenschaftsfehler, etc.)
  • tsconfig.json Fehler beheben (rootDir, outDir, paths)

🎯 Nächstes Kapitel

Herzlichen Glückwunsch! Sie haben alle Kapitel der TypeScript-Tutorial-Serie abgeschlossen! 🎉

Sie können jetzt:

  • ✅ TypeScript sicher verwenden
  • ✅ Komplexe Projekte mit TypeScript erstellen
  • ✅ Fehler effizient beheben

Viel Erfolg bei Ihren TypeScript-Projekten! 💪


❓ Häufig gestellte Fragen

F: Warum erhalte ich immer "Cannot find module" Fehler?

A: Stellen Sie sicher, dass Sie die entsprechenden Typdefinitionen installiert haben (@types/xxx).

F: Wie vermeide ich any?

A:

  1. Aktivieren Sie noImplicitAny in tsconfig.json
  2. Verwenden Sie spezifische Typen
  3. Verwenden Sie unknown statt any
  4. Verwenden Sie Generics für wiederverwendbare Funktionen

F: Warum kann TypeScript manche Fehler nicht erkennen?

A: TypeScript ist ein statischer Typenprüfer. Einige Fehler treten erst zur Laufzeit auf. Verwenden Sie immer strikte Einstellungen ("strict": true).


🎉 Herzlichen Glückwunsch! Sie haben Kapitel 13 und das gesamte TypeScript-Tutorial abgeschlossen! 🎉

Frei für alle Anfänger