Hrvatski

Istražite TypeScript diskriminirane unije, moćan alat za izgradnju robusnih i tipski sigurnih strojeva stanja. Naučite definirati stanja, rukovati prijelazima i iskoristiti TypeScriptov sustav tipova za povećanu pouzdanost koda.

TypeScript Diskriminirani Unioni: Izgradnja Tipski Sigurnih Strojeva Stanja

U području razvoja softvera, učinkovito upravljanje stanjem aplikacije je ključno. Strojevi stanja pružaju moćnu apstrakciju za modeliranje složenih sustava sa stanjima, osiguravajući predvidljivo ponašanje i pojednostavljujući razmišljanje o logici sustava. TypeScript, sa svojim robusnim sustavom tipova, nudi fantastičan mehanizam za izgradnju tipski sigurnih strojeva stanja koristeći diskriminirane unije (također poznate kao označene unije ili algebarske vrste podataka).

Što su Diskriminirani Unioni?

Diskriminirana unija je tip koji predstavlja vrijednost koja može biti jedan od nekoliko različitih tipova. Svaki od ovih tipova, poznatih kao članovi unije, dijeli zajedničko, različito svojstvo koje se naziva diskriminator ili oznaka. Ovaj diskriminator omogućuje TypeScriptu da precizno odredi koji je član unije trenutno aktivan, omogućujući moćnu provjeru tipova i automatsko dovršavanje.

Zamislite to kao semafor. Može biti u jednom od tri stanja: crveno, žuto ili zeleno. Svojstvo 'boja' djeluje kao diskriminator, govoreći nam točno u kojem je stanju svjetlo.

Zašto Koristiti Diskriminirane Unije za Strojeve Stanja?

Diskriminirani unioni donose nekoliko ključnih prednosti pri izgradnji strojeva stanja u TypeScriptu:

Definiranje Stroja Stanja s Diskriminiranim Unionima

Ilustrirajmo kako definirati stroj stanja pomoću diskriminiranih unija s praktičnim primjerom: sustav obrade narudžbi. Narudžba može biti u sljedećim stanjima: Na čekanju, Obrada, Poslano i Dostavljeno.

Korak 1: Definirajte Vrste Stanja

Prvo definiramo pojedinačne tipove za svako stanje. Svaki tip će imati svojstvo `type` koje djeluje kao diskriminator, zajedno sa svim podacima specifičnim za stanje.


interface Pending {
  type: "pending";
  orderId: string;
  customerName: string;
  items: string[];
}

interface Processing {
  type: "processing";
  orderId: string;
  assignedAgent: string;
}

interface Shipped {
  type: "shipped";
  orderId: string;
  trackingNumber: string;
}

interface Delivered {
  type: "delivered";
  orderId: string;
  deliveryDate: Date;
}

Korak 2: Stvorite Diskriminirani Union Tip

Zatim, stvaramo diskriminiranu uniju kombinirajući ove pojedinačne tipove pomoću operatora `|` (unija).


type OrderState = Pending | Processing | Shipped | Delivered;

Sada `OrderState` predstavlja vrijednost koja može biti `Pending`, `Processing`, `Shipped` ili `Delivered`. Svojstvo `type` unutar svakog stanja djeluje kao diskriminator, omogućujući TypeScriptu da ih razlikuje.

Rukovanje Prijelazima Stanja

Sada kada smo definirali naš stroj stanja, potreban nam je mehanizam za prijelaz između stanja. Napravimo funkciju `processOrder` koja uzima trenutno stanje i radnju kao ulaz i vraća novo stanje.


interface Action {
  type: string;
  payload?: any;
}

function processOrder(state: OrderState, action: Action): OrderState {
  switch (state.type) {
    case "pending":
      if (action.type === "startProcessing") {
        return {
          type: "processing",
          orderId: state.orderId,
          assignedAgent: action.payload.agentId,
        };
      }
      return state; // No state change

    case "processing":
      if (action.type === "shipOrder") {
        return {
          type: "shipped",
          orderId: state.orderId,
          trackingNumber: action.payload.trackingNumber,
        };
      }
      return state; // No state change

    case "shipped":
      if (action.type === "deliverOrder") {
        return {
          type: "delivered",
          orderId: state.orderId,
          deliveryDate: new Date(),
        };
      }
      return state; // No state change

    case "delivered":
      // Order is already delivered, no further actions
      return state;

    default:
      // This should never happen due to exhaustiveness checking
      return state; // Or throw an error
  }
}

Objašnjenje

Iskorištavanje Provjere Iscrpnosti

TypeScriptova provjera iscrpnosti moćna je značajka koja osigurava da obrađujete sva moguća stanja u vašem stroju stanja. Ako dodate novo stanje u uniju `OrderState`, ali zaboravite ažurirati funkciju `processOrder`, TypeScript će označiti pogrešku.

Da biste omogućili provjeru iscrpnosti, možete koristiti tip `never`. Unutar `default` slučaja vaše switch naredbe, dodijelite stanje varijabli tipa `never`.


function processOrder(state: OrderState, action: Action): OrderState {
  switch (state.type) {
    // ... (previous cases) ...

    default:
      const _exhaustiveCheck: never = state;
      return _exhaustiveCheck; // Or throw an error
  }
}

Ako `switch` naredba obrađuje sve moguće vrijednosti `OrderState`, varijabla `_exhaustiveCheck` bit će tipa `never` i kod će se kompajlirati. Međutim, ako dodate novo stanje u uniju `OrderState` i zaboravite ga obraditi u naredbi `switch`, varijabla `_exhaustiveCheck` bit će drugog tipa, a TypeScript će baciti pogrešku u vrijeme kompilacije, upozoravajući vas na slučaj koji nedostaje.

Praktični Primjeri i Primjene

Diskriminirani unioni primjenjivi su u širokom rasponu scenarija izvan jednostavnih sustava obrade narudžbi:

Primjer: Upravljanje Stanjem UI

Razmotrimo jednostavan primjer upravljanja stanjem UI komponente koja dohvaća podatke iz API-ja. Možemo definirati sljedeća stanja:


interface Initial {
  type: "initial";
}

interface Loading {
  type: "loading";
}

interface Success<T> {
  type: "success";
  data: T;
}

interface Error {
  type: "error";
  message: string;
}

type UIState<T> = Initial | Loading | Success<T> | Error;

function renderUI<T>(state: UIState<T>): React.ReactNode {
  switch (state.type) {
    case "initial":
      return <p>Click the button to load data.</p>;
    case "loading":
      return <p>Loading...</p>;
    case "success":
      return <pre>{JSON.stringify(state.data, null, 2)}</pre>;
    case "error":
      return <p>Error: {state.message}</p>;
    default:
      const _exhaustiveCheck: never = state;
      return _exhaustiveCheck;
  }
}

Ovaj primjer pokazuje kako se diskriminirani unioni mogu koristiti za učinkovito upravljanje različitim stanjima UI komponente, osiguravajući da se UI ispravno prikazuje na temelju trenutnog stanja. Funkcija `renderUI` ispravno obrađuje svako stanje, pružajući jasan i tipski siguran način upravljanja UI.

Najbolje Prakse za Korištenje Diskriminiranih Unija

Kako biste učinkovito koristili diskriminirane unije u svojim TypeScript projektima, razmotrite sljedeće najbolje prakse:

Napredne Tehnike

Uvjetni Tipovi

Uvjetni tipovi mogu se kombinirati s diskriminiranim unionima za stvaranje još moćnijih i fleksibilnijih strojeva stanja. Na primjer, možete koristiti uvjetne tipove za definiranje različitih tipova povratnih vrijednosti za funkciju na temelju trenutnog stanja.


function getData<T>(state: UIState<T>): T | undefined {
  if (state.type === "success") {
    return state.data;
  }
  return undefined;
}

Ova funkcija koristi jednostavnu `if` naredbu, ali bi se mogla učiniti robusnijom korištenjem uvjetnih tipova kako bi se osiguralo da se uvijek vrati određeni tip.

Utility Tipovi

TypeScriptovi utility tipovi, kao što su `Extract` i `Omit`, mogu biti korisni pri radu s diskriminiranim unionima. `Extract` vam omogućuje izdvajanje određenih članova iz union tipa na temelju uvjeta, dok vam `Omit` omogućuje uklanjanje svojstava iz tipa.


// Extract the "success" state from the UIState union
type SuccessState<T> = Extract<UIState<T>, { type: "success" }>;

// Omit the 'message' property from the Error interface
type ErrorWithoutMessage = Omit<Error, "message">;

Primjeri iz Stvarnog Svijeta u Različitim Industrijama

Snaga diskriminiranih unija proteže se kroz različite industrije i domene primjene:

Zaključak

TypeScript diskriminirani unioni pružaju moćan i tipski siguran način za izgradnju strojeva stanja. Jasnim definiranjem mogućih stanja i prijelaza, možete stvoriti robusniji, održiviji i razumljiviji kod. Kombinacija sigurnosti tipova, provjere iscrpnosti i poboljšanog dovršavanja koda čini diskriminirane unije neprocjenjivim alatom za svakog TypeScript programera koji se bavi složenim upravljanjem stanjem. Prihvatite diskriminirane unije u svom sljedećem projektu i iskusite prednosti tipski sigurnog upravljanja stanjem iz prve ruke. Kao što smo pokazali s različitim primjerima od e-trgovine do zdravstva i logistike do obrazovanja, načelo tipski sigurnog upravljanja stanjem putem diskriminiranih unija univerzalno je primjenjivo.

Bilo da gradite jednostavnu UI komponentu ili složenu poslovnu aplikaciju, diskriminirani unioni mogu vam pomoći da učinkovitije upravljate stanjem i smanjite rizik od pogrešaka izvođenja. Dakle, uronite i istražite svijet tipski sigurnih strojeva stanja s TypeScriptom!