TypeScript-Fehlerbehandlung

Die Fehlerbehandlung ist ein wichtiger Bestandteil, um die Robustheit von Programmen zu gewährleisten.

TypeScript bietet ein leistungsstarkes Typsystem, das Entwicklern helfen kann, Fehler besser zu behandeln und zu vermeiden.

Dieser Artikel stellt gängige Fehlerbehandlungsmuster und Best Practices in TypeScript vor.


SVG-Diagramm: Ansätze zur Fehlerbehandlung Background Title Error Handling Approaches Method 1: try-catch try-catch try { // code that may fail } catch (e) { // handle the error } Catch and handle exceptions Method 2: Result Type Result Type type Result = | { ok: true; value: T } | { ok: false; error: E } Return a result rather than throwing an exception Method 3: Error Types Custom errors class AppError extends Error { code: string; } Structured error information Bottom section Best Practices Practice 1 Specify error types clearly Practice 2 Centralized error handling Practice 3 Avoid exception leakage

Warum gute Fehlerbehandlung nötig ist

Jedes Programm kann auf Fehlersituationen stoßen, wie fehlgeschlagene Netzwerkanfragen, fehlende Dateien, ungültige Benutzereingaben und so weiter.

Eine gute Fehlerbehandlung kann Programmabstürze verhindern, freundliche Fehlermeldungen bereitstellen und Entwicklern helfen, Probleme zu lokalisieren.

Das Typsystem von TypeScript kann potenzielle Probleme zur Kompilierzeit finden und Laufzeitfehler reduzieren.

Konzepterklärung:Es gibt zwei Hauptarten, Fehler zu behandeln: Ausnahmebehandlung (try-catch) und Rückgabewertbehandlung (Result-Typ). Erstere löst Ausnahmen aus, um Fehler anzuzeigen, während letztere Fehlerinformationen über Rückgabewerte transportiert.


Benutzerdefinierte Fehlertypen

Erstelle benutzerdefinierte Fehlertypen, indem du die Error-Klasse erweiterst, sodass sie mehr Fehlerinformationen tragen können.

Dies macht die Fehlerbehandlung präziser und strukturierter.

Beispiel

// Anwendungsfehlerklasse definieren
// Die integrierte Error-Klasse erweitern und einen Fehlercode hinzufügen
class AppError extends Error {
    // Fehlercode für programmatische Fehlerbehandlung
    Code: string;

    // Konstruktor
    constructor(message: string, code: string) {
        super(message);  // Rufe den Konstruktor der Elternklasse auf
        this.name = "AppError";  // Setze den Fehlernamen
        this.code = code;  // Speichere den Fehlercode
    }
}

// Sichere Divisionsfunktion
function divide(a: number, b: number): number {
    // Prüfen, ob der Divisor null ist
    if (b === 0) {
        // Benutzerdefinierten Fehler auslösen
        throw new AppError("Division durch null nicht möglich", "DIVIDE_BY_ZERO");
    }
    return a / b;
}

// Verwende try-catch, um den Fehler abzufangen
try {
    var result = divide(10, 0);
} catch (error) {
    // Fehlertyp prüfen
    if (error instanceof AppError) {
        console.log("Anwendungsfehler: " + error.message + ", Code: " + error.code);
    } else {
        console.log("Unbekannter Fehler: " + error);
    }
}

Ausgabe:

应用错误: Cannot divide by zero, 代码: DIVIDE_BY_ZERO

Fehlercode:Das Hinzufügen von Codes zu Fehlern hilft dem Programm, verschiedene Arten von Fehlern präziser zu behandeln.


Result-Typ zur Vermeidung von Ausnahmen

Ein weiterer Ansatz zur Fehlerbehandlung ist die Verwendung des Result-Typs.

Er übermittelt Fehlerinformationen über Rückgabewerte, anstatt Ausnahmen auszulösen. Dieser Ansatz ist in der funktionalen Programmierung üblich.

Beispiel

// Definiere einen Result-Typ mithilfe eines Union-Typs
// Bei Erfolg enthält er ok: true und einen Wert; im Fehlerfall enthält er ok: false und einen Fehler
type Result<T, E = Error> =
    | { ok: true; value: T }
    | { ok: false; error: E };

// Divisionsfunktion mit dem Result-Typ
function safeDivide(a: number, b: number): Result<number, string> {
    // Prüfen, ob der Divisor null ist
    if (b === 0) {
        // Ein Fehlerergebnis zurückgeben
        return { ok: false, error: "Division durch Null nicht möglich" };
    }
    // Ein Erfolgsergebnis zurückgeben
    return { ok: true, value: a / b };
}

// Die Funktion aufrufen und das Ergebnis verarbeiten
var result = safeDivide(10, 2);

// Basierend auf dem Result-Typ verarbeiten
if (result.ok) {
    console.log("Ergebnis: " + result.value);
} else {
    console.log("Fehler: " + result.error);
}

Ausgabe:

结果: 5

Vorteile:Der Result-Typ macht die Fehlerbehandlung explizit; Aufrufer müssen mögliche Fehler behandeln und können sie nicht ignorieren.


Fehlerbehandlung in asynchronen Funktionen

In asynchronen Funktionen ist die Fehlerbehandlung besonders wichtig.

Sie können try-catch oder den Result-Typ verwenden, um Fehler in asynchronen Operationen zu behandeln.

Beispiel

// Ein User-Interface definieren
interface User {
    id: number;
    name: string;
}

// Simuliere eine asynchrone Funktion zum Abrufen eines Benutzers
async function fetchUser(id: number): Promise<Result<User, Error>> {
    try {
        // Simuliere eine Netzwerkanfrage
        var response = await fetch("/api/users/" + id);
        var user = await response.json();
        // Ein Erfolgsergebnis zurückgeben
        return { ok: true, value: user };
    } catch (error) {
        // Ein Fehlerergebnis zurückgeben
        return { ok: false, error: error as Error };
    }
}

// Hauptfunktion
async function main() {
    // Asynchrone Funktion aufrufen
    var result = await fetchUser(1);

    // Das Ergebnis verarbeiten
    if (result.ok) {
        console.log("Benutzer: " + JSON.stringify(result.value));
    } else {
        console.log("Fehler: " + result.error.message);
    }
}

// Hauptfunktion ausführen
main();

Ausgabe:

User: {"id":1,"name":"Alice"}

Tipp:Das try-catch in einer async-Funktion fängt jeden Fehler ab, der von await-Ausdrücken geworfen wird.


Allgemeiner Wrapper zur Fehlerbehandlung

Du kannst eine allgemeine Funktion zur Fehlerbehandlung erstellen, um die Fehlerbehandlung in asynchronem Code zu vereinfachen.

Beispiel

// Allgemeine Wrapper-Funktion zur Fehlerbehandlung
// Eine async-Funktion annehmen und einen Result-Typ zurückgeben
async function withErrorHandling<T>(
    fn: () => Promise<T>
): Promise<Result<T, Error>> {
    try {
        // Führe die übergebene async-Funktion aus
        var data = await fn();
        // Ein Erfolgsergebnis zurückgeben
        return { ok: true, value: data };
    } catch (error) {
        // Ein Fehlerergebnis zurückgeben
        return { ok: false, error: error as Error };
    }
}

// Allgemeine Fehlerbehandlung verwenden
// Datenabruf simulieren
var result = await withErrorHandling(async function() {
    var response = await fetch("/api/data");
    return response.json();
});

// Basierend auf dem Ergebnis behandeln
if (result.ok) {
    console.log("Daten: " + JSON.stringify(result.value));
} else {
    console.error("Error:", result.error);
}

Bewährte Praxis:Das Kapseln allgemeiner Fehlerbehandlungslogik reduziert Codeduplizierung und verbessert die Wartbarkeit des Codes.


Hinweise

  • Fehler nicht ignorieren:Verwenden Sie keine leeren catch-Blöcke, um Fehler abzufangen und zu ignorieren
  • Fehlertypen klar angeben:Verwenden Sie nach Möglichkeit spezifische Fehlertypen statt des generischen Error
  • Fehlergrenzen:Richten Sie einen einheitlichen Fehlerbehandlungsmechanismus in der Anwendung ein
  • Ausnahmen nicht übermäßig verwenden:Bevorzugen Sie bei vorhersehbaren Fehlern Rückgabewerte gegenüber dem Werfen von Ausnahmen

Vorschlag:Wählen Sie einen Fehlerbehandlungsansatz je nach Szenario: Verwenden Sie Ausnahmen für Programmfehler und Result für fachliche Fehler.


Zusammenfassung

Eine gute Fehlerbehandlung ist die Grundlage für den Aufbau robuster Anwendungen.

  • Benutzerdefinierte Fehler:Erweitern Sie die Error-Klasse und fügen Sie Informationen wie Fehlercodes hinzu
  • Result-Typ:Behandeln Sie Fehler über Rückgabewerte und vermeiden Sie Ausnahmen
  • async/await:Verwenden Sie try-catch für asynchrone Fehler
  • Fehler-Wrapping:Erstellen Sie allgemeine Fehlerbehandlungsfunktionen
  • Fehlergrenzen:Einen einheitlichen Mechanismus zur Fehlerbehandlung einrichten

Best Practice:Wählen Sie je nach konkretem Szenario einen geeigneten Ansatz für die Fehlerbehandlung, der Code-Lesbarkeit und Robustheit in Einklang bringt.


Andere Erweiterungen