Gestion des erreurs TypeScript

La gestion des erreurs est un élément important pour garantir la robustesse d'un programme.

TypeScript fournit un système de types puissant qui peut aider les développeurs à mieux gérer et prévenir les erreurs.

Cet article présente les modèles courants de gestion des erreurs et les bonnes pratiques en TypeScript.


Diagramme SVG : Approches de gestion des erreurs 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

Pourquoi une bonne gestion des erreurs est nécessaire

Tout programme peut rencontrer des situations d'erreur, telles que des échecs de requêtes réseau, des fichiers manquants, une saisie utilisateur invalide, etc.

Une bonne gestion des erreurs peut empêcher le programme de planter, fournir des messages d'erreur conviviaux et aider les développeurs à localiser les problèmes.

Le système de types de TypeScript peut détecter les problèmes potentiels au moment de la compilation, ce qui réduit les erreurs d'exécution.

Explication du concept :Il existe deux manières principales de gérer les erreurs : la gestion des exceptions (try-catch) et la gestion par valeur de retour (type Result). La première lance des exceptions pour indiquer des erreurs, tandis que la seconde transporte les informations d'erreur via les valeurs de retour.


Types d'erreurs personnalisés

Créez des types d'erreur personnalisés en étendant la classe Error, ce qui leur permet de transporter davantage d'informations d'erreur.

Cela rend la gestion des erreurs plus précise et structurée.

Exemple

// Définir la classe d'erreur de l'application
// Étendre la classe Error intégrée et ajouter un code d'erreur
class AppError extends Error {
    // Code d'erreur pour la gestion programmatique des erreurs
    code: string;

    // Constructeur
    constructor(message: string, code: string) {
        super(message);  // Appeler le constructeur de la classe parente
        this.name = "AppError";  // Définir le nom de l'erreur
        this.code = code;  // Enregistrer le code d'erreur
    }
}

// Fonction de division sécurisée
function divide(a: number, b: number): number {
    // Vérifier si le diviseur est zéro
    if (b === 0) {
        // Lancer une erreur personnalisée
        throw new AppError("Impossible de diviser par zéro", "DIVIDE_BY_ZERO");
    }
    return a / b;
}

// Utiliser try-catch pour intercepter l'erreur
try {
    var result = divide(10, 0);
} catch (error) {
    // Vérifier le type d'erreur
    if (error instanceof AppError) {
        console.log("Erreur d'application : " + error.message + ", code : " + error.code);
    } else {
        console.log("Erreur inconnue : " + error);
    }
}

Sortie :

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

Code d'erreur :L'ajout de codes aux erreurs aide le programme à gérer différents types d'erreurs plus précisément.


Type Result pour éviter les exceptions

Une autre approche de gestion des erreurs consiste à utiliser le type Result.

Il transporte les informations d'erreur via des valeurs de retour au lieu de lever des exceptions. Cette approche est courante en programmation fonctionnelle.

Exemple

// Définir un type Result à l'aide d'un type union
// En cas de succès, inclut ok: true et une valeur ; en cas d'échec, inclut ok: false et une erreur
type Result<T, E = Error> =
    | { ok: true; value: T }
    | { ok: false; error: E };

// Fonction de division utilisant le type Result
function safeDivide(a: number, b: number): Result<number, string> {
    // Vérifier si le diviseur est zéro
    if (b === 0) {
        // Renvoyer un résultat d'erreur
        return { ok: false, error: "Impossible de diviser par zéro" };
    }
    // Renvoyer un résultat de succès
    return { ok: true, value: a / b };
}

// Appeler la fonction et gérer le résultat
var result = safeDivide(10, 2);

// Gérer selon le type de résultat
if (result.ok) {
    console.log("Résultat : " + result.value);
} else {
    console.log("Erreur : " + result.error);
}

Sortie :

结果: 5

Avantages :Le type Result rend la gestion des erreurs explicite ; les appelants doivent gérer les erreurs possibles et ne peuvent pas les ignorer.


Gestion des erreurs des fonctions asynchrones

Dans les fonctions asynchrones, la gestion des erreurs est particulièrement importante.

Vous pouvez utiliser try-catch ou le type Result pour gérer les erreurs dans les opérations asynchrones.

Exemple

// Définir une interface pour l'utilisateur
interface User {
    id: number;
    name: string;
}

// Simuler une fonction asynchrone pour récupérer un utilisateur
async function fetchUser(id: number): Promise<Result<User, Error>> {
    try {
        // Simuler une requête réseau
        var response = await fetch("/api/users/" + id);
        var user = await response.json();
        // Renvoyer un résultat de succès
        return { ok: true, value: user };
    } catch (error) {
        // Renvoyer un résultat d'erreur
        return { ok: false, error: error as Error };
    }
}

// Fonction principale
async function main() {
    // Appeler la fonction asynchrone
    var result = await fetchUser(1);

    // Gérer le résultat
    if (result.ok) {
        console.log("Utilisateur : " + JSON.stringify(result.value));
    } else {
        console.log("Erreur : " + result.error.message);
    }
}

// Exécuter la fonction principale
main();

Sortie :

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

Astuce :Le try-catch dans une fonction asynchrone capture toute erreur levée par les expressions await.


Wrapper général de gestion des erreurs

Vous pouvez créer une fonction générale de gestion des erreurs pour simplifier la gestion des erreurs dans le code asynchrone.

Exemple

// Fonction wrapper générale de gestion des erreurs
// Accepte une fonction asynchrone et retourne un type Result
async function withErrorHandling<T>(
    fn: () => Promise<T>
): Promise<Result<T, Error>> {
    try {
        // Exécuter la fonction async transmise
        var data = await fn();
        // Renvoyer un résultat de succès
        return { ok: true, value: data };
    } catch (error) {
        // Renvoyer un résultat d'erreur
        return { ok: false, error: error as Error };
    }
}

// Utiliser la gestion générale des erreurs
// Simuler la récupération de données
var result = await withErrorHandling(async function() {
    var response = await fetch("/api/data");
    return response.json();
});

// Gérer en fonction du résultat
if (result.ok) {
    console.log("Données : " + JSON.stringify(result.value));
} else {
    console.error("Error:", result.error);
}

Bonne pratique :Encapsuler la logique générale de gestion des erreurs réduit la duplication de code et améliore la maintenabilité du code.


Notes

  • N'ignorez pas les erreurs :N'utilisez pas de blocs catch vides pour capturer et ignorer les erreurs
  • Spécifiez clairement les types d'erreur :Utilisez des types d'erreur spécifiques autant que possible, plutôt que le type Error générique
  • Limites d'erreur :Établissez un mécanisme unifié de gestion des erreurs dans l'application
  • N'abusez pas des exceptions :Pour les erreurs prévisibles, préférez les valeurs de retour à la levée d'exceptions

Suggestion :Choisissez une approche de gestion des erreurs en fonction du scénario : utilisez des exceptions pour les erreurs de programme, et Result pour les erreurs métier.


Résumé

Une bonne gestion des erreurs est la base pour construire des applications robustes.

  • Erreurs personnalisées :Étendez la classe Error et ajoutez des informations telles que des codes d'erreur
  • Type Result :Gérez les erreurs via des valeurs de retour, en évitant les exceptions
  • async/await:Utilisez try-catch pour les erreurs asynchrones
  • Encapsulation des erreurs :Créez des fonctions générales de gestion des erreurs
  • Limites d'erreur :Établir un mécanisme unifié de gestion des erreurs

Bonne pratique :Choisissez une approche de gestion des erreurs appropriée en fonction du scénario spécifique, en équilibrant la lisibilité et la robustesse du code.


Autres extensions