Główne logo strony
TypeScript

Typ never i obsługa błędów


Typ never w TypeScript reprezentuje zbiór pusty – oznacza, że żadna wartość nie może być tego typu. Używany jest do modelowania stanów, które nigdy nie powinny się wydarzyć, np. w kontekście obsługi błędów lub wyczerpywania przypadków w strukturach typu switch.

Przykład zastosowania w funkcjach

Typ never może być szczególnie użyteczny w funkcjach, aby upewnić się, że wszystkie możliwe przypadki zostały obsłużone.

type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Rectangle = { kind: "rectangle"; width: number; height: number };

type Shape = Circle | Square | Rectangle;

function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}

function area(s: Shape): number {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.radius ** 2;
    case "square":
      return s.side ** 2;
    case "rectangle":
      return s.width * s.height;
    default:
      return assertNever(s); // Typ `never` zapewnia, że wszystkie przypadki są obsłużone
  }
}

W powyższym przykładzie, funkcja assertNever rzuca błąd, jeśli otrzyma wartość, która nie jest jednym z oczekiwanych typów (Circle, Square, Rectangle). Dzięki temu TypeScript podpowie nam, jeśli w przyszłości dodamy nowy typ do unii Shape, a zapomnimy zaktualizować funkcję area 👏

Obsługa błędów za pomocą unii dyskryminowanych (discriminated union)

Innym sposobem na bardziej elegancką obsługę błędów w TypeScript jest wykorzystanie typów unii dyskryminowanych.

type ErrorT = { kind: "error"; error: string };
type Success<T> = { kind: "success"; value: T };

type Result<T> = ErrorT | Success<T>;

function error(msg: string): ErrorT {
  return { kind: "error", error: msg };
}

function success<T>(value: T): Success<T> {
  return { kind: "success", value };
}

function divide(a: number, b: number): Result<number> {
  if (b === 0) {
    return error("Division by zero");
  }
  return success(a / b);
}

const result = divide(10, 0);

if (result.kind === "error") {
  console.error(result.error);
} else {
  console.log(result.value);
}

W tym przypadku, funkcja divide zwraca typ Result<number>, który może być albo sukcesem (Success<number>), albo błędem (ErrorT). Taki sposób definiowania błędów daje większą przejrzystość i lepszą kontrolę nad stanami aplikacji.

Zobacz również:

Losowy shortKolejny short: TypeScript