jambit-TP150-elegant-error-handling-with-typescript-icon

Try but don't catch: Elegantes Error-Handling geht auch mit TypeScript

Problem

Keine Lust mehr auf throw? Keine Lust mehr darauf, für jeden Rückgabewert mittels If zu checken, ob der Wert auch wirklich angekommen ist? Keine Lust mehr auf Boilerplate Code mit try/catch? Ihr sucht eine Implementierung der Result-/Optional-/Maybe-Monade? Oder habt mal etwas von Railway Oriented Programming gehört und wollt das mal ausprobieren?

Lösung

Wenn ihr im TypeScript unterwegs seid, gibt es da ein schönes Tool für euch – neverthrow! Wie der Name schon sagt, schreibt ihr damit Code, der keine Fehler mehr wirft oder fängt. Stattdessen gibt es einen Result-Typen, welcher die Zustände Ok oder Err annehmen kann. Das Beste daran ist, dass ihr ganz im Sinne des Railway Oriented Programming verschiedene Results aneinander "ketten" und zwischen den Zuständen wechseln könnt, d.h. in den Err-Zustand übergehen oder sogar aus dem Err-Zustand wieder in den Ok-Zustand "recovern". Als wäre das noch nicht genug, bietet die Lib auch Interoperabilität mit Promise durch den ResultAsync-Typen.

Beispiel

function hasKeys<T extends object>(item: T, keys: Array<keyof T>): Result<T, string> {
  const requiredKeysArePresent = keys.every((key) => key in item);
  return requiredKeysArePresent ? ok(item) : err('Object to validate has missing keys');
}
// Using the synchronous Result API
async function storeCoffee(candidate?: Coffee): Promise<void> {
  const validationResult: Result<Coffee, string> = exists(candidate)
    // Only if Ok is returned, the code is continued in "andThen"
    .andThen((existingCandidate) => hasKeys(existingCandidate, ['name', 'origin']));
  if (validationResult.isOk()) {
    await saveCoffeeInDb(validationResult.value);
  }
}
// Converting a Promise to ResultAsync
function get<T>(url: string): ResultAsync<T, ApiError> {
  return fromPromise(
    httpClient.get<T>(url, { responseType: 'json' }).then((result) => result.body),
    (e) => mapToApiError(e)); // Replacement for the "catch" method of Promise
}
function getCoffeeList(): Promise<Coffee[]> {
  return get<Coffee[]>('api.jambit.com/coffee')
    .mapErr((e: ApiError) => {
      logger.error(`Could not get coffee list because of: ${e}`);
      return [coffeeA, coffeeB]; // Recover with fallback value
    }).match((coffeeList: Coffee[]) => {
        logger.info(`There are ${coffeeList.length} types of coffee available.`);
        return coffeeList;
      }, (fallbackList) => fallbackList));
}
jambit tp150-error handling with TypeScript

Weiterführende Aspekte

---

Autor: Robert Gruner / Software Engineer / Standort Leipzig

Cookie-Einstellungen

Diese Website verwendet Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und Zugriffe auf die Website zu analysieren. Zudem werden Informationen zu Ihrer Verwendung der Website an Partner für soziale Medien, Werbung und Analysen weitergegeben. Die Partner führen diese Informationen möglicherweise mit weiteren Daten zusammen, die Sie ihnen bereitgestellt haben oder die sie im Rahmen Ihrer Nutzung der Dienste gesammelt haben.

Weitere Informationen finden Sie in unserer Datenschutzerklärung. Dort können Sie nachträglich auch Ihre Cookie-Einstellungen ändern.

contact icon

Kontakt aufnehmen