TypeScript-Typfehler verstehen und beheben
TypeScript fügt JavaScript statische Typisierung hinzu, was hilft, Fehler früh in der Entwicklung zu erkennen. Dies kann jedoch zu Typ-bezogenen Fehlern führen, die anfangs verwirrend sein können. Das Verständnis dieser Fehler hilft dir, zuverlässigeren Code zu schreiben und das TypeScript-Typsystem effektiv zu nutzen.
Typfehler verstehen
TypeScript-Typfehler treten auf bei:
-
Typ-Nichtübereinstimmungen:
- Zuweisung inkompatibler Werte
- Übergabe falscher Argumente
- Rückgabe falscher Typen
-
Fehlende Typdefinitionen:
- Undefinierte Eigenschaften
- Fehlende Interface-Implementierungen
- Unvollständige Typdeklarationen
-
Typinferenz-Probleme:
- Implizite any-Typen
- Komplexe Union-Typen
- Generische Typbeschränkungen
Häufige TypeScript-Fehler
1. Typzuweisungsfehler
// Typfehler bei Zuweisung let alter: number = "25"; // Type 'string' is not assignable to type 'number' // Objekteigenschaft-Typfehler interface Benutzer { id: number; name: string; } const benutzer: Benutzer = { id: "123", // Type 'string' is not assignable to type 'number' name: "Max" }; // Array-Typfehler const zahlen: number[] = [1, 2, "3"]; // Type 'string' is not assignable to type 'number'
2. Funktionsparameter-Fehler
// Parameter-Typfehler function begrüße(name: string) { console.log(`Hallo, ${name}`); } begrüße(123); // Argument of type 'number' is not assignable to parameter of type 'string' // Optionale Parameter-Fehler function verarbeite(daten: string, optionen?: { debug: boolean }) { console.log(optionen.debug); // Object is possibly 'undefined' } // Rest-Parameter-Typfehler function summe(...zahlen: number[]) { return zahlen.reduce((a, b) => a + b, 0); } summe(1, "2", 3); // Argument of type 'string' is not assignable to parameter of type 'number'
3. Interface- und Typdefinitions-Fehler
// Fehlende erforderliche Eigenschaften interface Konfiguration { host: string; port: number; sicher: boolean; } const config: Konfiguration = { host: "localhost", port: 3000 // Property 'sicher' is missing in type '{ host: string; port: number; }' }; // Überschüssige Eigenschaftsprüfungen interface Optionen { farbe?: string; größe?: number; } const optionen: Optionen = { farbe: "rot", größe: 42, gewicht: 100 // Object literal may only specify known properties }; // Interface-Vererbungsfehler interface Tier { name: string; art: string; } interface Hund extends Tier { rasse: string; art: number; // Interface 'Hund' incorrectly extends interface 'Tier' }
4. Generische Typfehler
// Constraint-Verletzungen function getEigenschaft<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const obj = { a: 1, b: 2 }; getEigenschaft(obj, "c"); // Argument of type '"c"' is not assignable to parameter of type '"a" | "b"' // Generische Typinferenz-Probleme class Container<T> { private wert: T; constructor(wert: T) { this.wert = wert; } getWert(): T { return this.wert; } } const container = new Container("hallo"); const wert: number = container.getWert(); // Type 'string' is not assignable to type 'number'
5. Typ-Assertions-Fehler
// Falsche Typ-Assertions const wert: any = "hallo"; const länge: number = (wert as number).toFixed(2); // Laufzeitfehler! // Nicht überlappende Typ-Assertions interface Katze { miauen(): void; } interface Hund { bellen(): void; } const haustier = { bellen() { console.log("Wuff!"); } }; const katze = haustier as Katze; // Conversion of type '{ bellen(): void; }' to type 'Katze' may be a mistake
Wie erkennst du Probleme?
-
IDE-Integration:
- TypeScript-Sprachdienst-Fehler
- Inline-Typhinweise
- Schnelle Behebungsvorschläge
-
Compiler-Optionen:
// tsconfig.json { "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true } }
-
ESLint TypeScript-Regeln:
// .eslintrc.js module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking' ] };
Vorbeugung und beste Praktiken
1. Strikte Typprüfung verwenden
// Aktiviere den strikten Modus in tsconfig.json { "compilerOptions": { "strict": true, // Dies aktiviert: // - noImplicitAny // - strictNullChecks // - strictFunctionTypes // - strictBindCallApply // - strictPropertyInitialization // - noImplicitThis // - alwaysStrict } }
2. Type Guards und Type Narrowing
// Type Guards function istString(wert: unknown): wert is string { return typeof wert === "string"; } function verarbeiteWert(wert: unknown) { if (istString(wert)) { console.log(wert.toUpperCase()); // TypeScript weiß, dass wert ein String ist } } // Type Narrowing mit instanceof class ApiFehler extends Error { code: number; constructor(nachricht: string, code: number) { super(nachricht); this.code = code; } } function behandleFehler(fehler: unknown) { if (fehler instanceof ApiFehler) { console.log(fehler.code); // TypeScript weiß, dass fehler ein ApiFehler ist } }
3. Korrekte Verwendung von Generics
// Generische Constraints interface HatLänge { length: number; } function logLänge<T extends HatLänge>(wert: T): number { return wert.length; } // Funktioniert mit Strings und Arrays logLänge("hallo"); // 5 logLänge([1, 2, 3]); // 3 logLänge(42); // Fehler: number hat keine length-Eigenschaft // Generische Standardwerte interface ApiAntwort<T = any> { daten: T; status: number; } function holeDaten<T>(): Promise<ApiAntwort<T>> { // Implementierung }
Häufige Fehler, die du vermeiden solltest
-
Typ-Assertions statt Type Guards:
// Schlecht: Verwendung von Typ-Assertion function verarbeiteWert(wert: unknown) { const str = wert as string; console.log(str.toUpperCase()); // Könnte zur Laufzeit fehlschlagen } // Gut: Verwendung von Type Guard function verarbeiteWert(wert: unknown) { if (typeof wert === "string") { console.log(wert.toUpperCase()); // Sicher } }
-
Ignorieren von Null-Werten:
// Schlecht: Ignorieren von möglichem null function getLetzterEintrag<T>(array: T[]): T { return array[array.length - 1]; // Könnte undefined sein } // Gut: Behandlung von Null-Werten function getLetzterEintrag<T>(array: T[]): T | undefined { return array.length > 0 ? array[array.length - 1] : undefined; }
-
Übermäßige Verwendung von
any
:// Schlecht: Übermäßige Verwendung von any function verarbeiteDaten(daten: any) { return daten.eigenschaft.methode(); // Keine Typsicherheit } // Gut: Verwendung korrekter Typen interface DatenTyp { eigenschaft: { methode(): void; }; } function verarbeiteDaten(daten: DatenTyp) { return daten.eigenschaft.methode(); // Typsicher }
Denk dran: Das TypeScript-Typsystem ist dafür da, dir zu helfen, Fehler früh zu erkennen. Anstatt dagegen anzukämpfen oder Typ-Assertions zu verwenden, um Fehler zu unterdrücken, nutze seine Funktionen, um zuverlässigeren Code zu schreiben.