0Pricing
TypeScript Academy · Lekcja

Typy w stylu Result/Either

Modelujcie powodzenie i niepowodzenie jawnie za pomocą unii Result/Either, dodajcie funkcje pomocnicze (map/flatMap/mapError) i zachowajcie przewidywalność przepływów bez stosowania try/catch wszędzie.

Typy w stylu Result/Either to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 1 z 2. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 2 lekcji w sumie.

Wprowadzenie

Cel: Spraw, aby błędy były widoczne. Zamodelujesz wyniki za pomocą unii dyskryminowanej, połączysz operacje przy użyciu helperów i przekonwertujesz wyjątki na granicy systemu.

  • Typ Result
  • map/flatMap/mapError
  • Integracja z HTTP

Rdzeń Result

Utwórz niewielkie narzędzie Result: konstruktory ok/err oraz funkcje map, flatMap i mapError do składania operacji.

export type Ok<T>  = { ok: true;  value: T }
export type Err<E> = { ok: false; error: E }
export type Result<T, E> = Ok<T> | Err<E>

export const ok = <T>(value: T): Ok<T> => ({ ok: true, value })
export const err = <E>(error: E): Err<E> => ({ ok: false, error })

export function map<T, E, U>(r: Result<T, E>, f: (t: T) => U): Result<U, E> {
  return r.ok ? ok(f(r.value)) : r
}
export function flatMap<T, E, U>(r: Result<T, E>, f: (t: T) => Result<U, E>): Result<U, E> {
  return r.ok ? f(r.value) : r
}
export function mapError<T, E, F>(r: Result<T, E>, g: (e: E) => F): Result<T, F> {
  return r.ok ? r : err(g(r.error))
}

Błędy domenowe

Modeluj błędy domenowe jako unię dyskryminowaną ze znacznikiem tag. Każdy wariant zawiera precyzyjne dane potrzebne do tworzenia dobrych komunikatów.

export type CreateUserError =
  | { tag: "InvalidEmail"; detail?: string }
  | { tag: "Duplicate"; email: string }

export function validateEmail(email: string): Result<string, CreateUserError> {
  const okEmail = /.+@.+/.test(email)
  return okEmail ? ok(email.toLowerCase()) : err({ tag: "InvalidEmail", detail: "bad format" })
}

const existing = new Set(["ada@example.com"]) // pretend DB
export function saveUser(email: string): Result<{ id: string }, CreateUserError> {
  if (existing.has(email)) return err({ tag: "Duplicate", email })
  return ok({ id: Math.random().toString(36).slice(2) })
}

Składanie przepływów

Łącz walidacje za pomocą flatMap. Używaj switch wraz ze sprawdzeniem never, aby wymusić pełną obsługę wariantów w czasie kompilacji.

export function createUser(flowEmail: string) {
  return flatMap(validateEmail(flowEmail), email => saveUser(email))
}

// Use
const r = createUser("Ada@example.com")
if (r.ok) {
  console.log("id:", r.value.id)
} else {
  switch (r.error.tag) {
    case "InvalidEmail": console.error("invalid email:", r.error.detail); break
    case "Duplicate": console.error("already used:", r.error.email); break
    default: ((x: never) => x)(r.error) // exhaustiveness
  }
}

Wyjątek → Result

Na granicach operacji wejścia-wyjścia opakuj wyjątki i przekonwertuj je na Result. Kod wywołujący zachowuje jedną ścieżkę obsługi błędów.

export async function fromPromise<T>(p: Promise<T>): Promise<Result<T, { tag: "Exception"; message: string }>> {
  try { return ok(await p) }
  catch (e) { return err({ tag: "Exception", message: e instanceof Error ? e.message : String(e) }) }
}

// Example: wrap a fetch
export async function fetchJson<T>(url: string): Promise<Result<T, { tag: "Exception"; message: string }>> {
  return fromPromise(fetch(url).then(r => r.json() as T))
}

Wskazówki dotyczące mapowania HTTP

Integracja z HTTP: mapuj błędy domenowe na 400/409, a wyjątki operacji wejścia-wyjścia na 502/503. Utrzymuj niewielką funkcję mapującą, aby kontrolery pozostały przejrzyste i przewidywalne.

Sprawdzenie korzyści z Result

Szybkie sprawdzenie: Dlaczego warto preferować unię dyskryminowaną Result?

Podsumowanie

Podsumowanie: Zdefiniuj niewielki typ Result, łącz operacje za pomocą map/flatMap, modeluj błędy domenowe jako unie i konwertuj wyjątki na granicach systemu.

Często zadawane pytania

Czy lekcja „Typy w stylu Result/Either” jest bezpłatna?

Tak — pełny tekst „Typy w stylu Result/Either” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 2 lekcji w sumie.

Co nauczysz się w „Typy w stylu Result/Either”?

Modelujcie powodzenie i niepowodzenie jawnie za pomocą unii Result/Either, dodajcie funkcje pomocnicze (map/flatMap/mapError) i zachowajcie przewidywalność przepływów bez stosowania try/catch wszędzi… Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?

Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 2.

Ile czasu zajmuje lekcja „Typy w stylu Result/Either”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?

Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Typy w stylu Result/Either
  2. Kompletna obsługa błędów za pomocą unii rozróżnianych
← Powrót do TypeScript Academy