Čeština

Prozkoumejte TypeScript rozlišené unie, silný nástroj pro vytváření robustních a typově bezpečných stavových automatů. Naučte se definovat stavy, zpracovávat přechody a využívat typový systém TypeScript pro zvýšení spolehlivosti kódu.

TypeScript Rozlišené Unie: Vytváření stavových automatů s bezpečným typem

V oblasti vývoje softwaru je efektivní správa stavu aplikace zásadní. Stavové automaty poskytují výkonnou abstrakci pro modelování složitých systémů se stavem, zajišťují předvídatelné chování a zjednodušují úvahy o logice systému. TypeScript se svým robustním typovým systémem nabízí fantastický mechanismus pro vytváření stavových automatů s bezpečným typem pomocí rozlišených unií (také známých jako označené unie nebo algebraické datové typy).

Co jsou Rozlišené Unie?

Rozlišená unie je typ, který reprezentuje hodnotu, která může být jedním z několika různých typů. Každý z těchto typů, známý jako člen unie, sdílí společnou, odlišnou vlastnost nazvanou diskriminant nebo tag. Tento diskriminant umožňuje TypeScriptu přesně určit, který člen unie je aktuálně aktivní, což umožňuje výkonnou kontrolu typů a automatické dokončování.

Představte si to jako semafor. Může být v jednom ze tří stavů: Červená, Žlutá nebo Zelená. Vlastnost 'color' funguje jako diskriminant a říká nám přesně, v jakém stavu je světlo.

Proč Používat Rozlišené Unie pro Stavové Automaty?

Rozlišené unie přinášejí několik klíčových výhod při vytváření stavových automatů v TypeScriptu:

Definování Stavového Automatu s Rozlišenými Uniemi

Pojďme si ukázat, jak definovat stavový automat pomocí rozlišených unií s praktickým příkladem: systém zpracování objednávek. Objednávka může být v následujících stavech: Čeká se, Zpracovává se, Odesláno a Doručeno.

Krok 1: Definujte Typy Stavů

Nejprve definujeme jednotlivé typy pro každý stav. Každý typ bude mít vlastnost `type` fungující jako diskriminant spolu s jakýmikoli daty specifickými pro daný stav.


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;
}

Krok 2: Vytvořte Typ Rozlišené Unie

Dále vytvoříme rozlišenou unii kombinací těchto jednotlivých typů pomocí operátoru `|` (unie).


type OrderState = Pending | Processing | Shipped | Delivered;

Nyní `OrderState` reprezentuje hodnotu, která může být buď `Pending`, `Processing`, `Shipped` nebo `Delivered`. Vlastnost `type` v každém stavu funguje jako diskriminant a umožňuje TypeScriptu je rozlišovat.

Zpracování Přechodů Stavů

Nyní, když jsme definovali náš stavový automat, potřebujeme mechanismus pro přechod mezi stavy. Vytvořme funkci `processOrder`, která přijímá aktuální stav a akci jako vstup a vrací nový stav.


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
  }
}

Vysvětlení

Využití Kontroly Vyčerpání

Kontrola vyčerpání TypeScriptu je výkonná funkce, která zajišťuje, že zpracujete všechny možné stavy ve vašem stavovém automatu. Pokud přidáte nový stav do unie `OrderState`, ale zapomenete aktualizovat funkci `processOrder`, TypeScript označí chybu.

Chcete-li povolit kontrolu vyčerpání, můžete použít typ `never`. Uvnitř případu `default` ve vašem příkazu switch přiřaďte stav proměnné typu `never`.


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

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

Pokud příkaz `switch` zpracovává všechny možné hodnoty `OrderState`, proměnná `_exhaustiveCheck` bude typu `never` a kód se zkompiluje. Pokud však přidáte nový stav do unie `OrderState` a zapomenete jej zpracovat v příkazu `switch`, proměnná `_exhaustiveCheck` bude mít jiný typ a TypeScript vyvolá chybu v době kompilace, čímž vás upozorní na chybějící případ.

Praktické Příklady a Aplikace

Rozlišené unie jsou použitelné v široké škále scénářů mimo jednoduché systémy zpracování objednávek:

Příklad: Správa Stavů UI

Zvažme jednoduchý příklad správy stavu komponenty UI, která načítá data z API. Můžeme definovat následující stavy:


interface Initial {
  type: "initial";
}

interface Loading {
  type: "loading";
}

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

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

type UIState = Initial | Loading | Success | Error;

function renderUI(state: UIState): React.ReactNode {
  switch (state.type) {
    case "initial":
      return 

Klikněte na tlačítko pro načtení dat.

; case "loading": return

Načítání...

; case "success": return
{JSON.stringify(state.data, null, 2)}
; case "error": return

Chyba: {state.message}

; default: const _exhaustiveCheck: never = state; return _exhaustiveCheck; } }

Tento příklad ukazuje, jak lze rozlišené unie použít k efektivní správě různých stavů komponenty UI, což zajišťuje, že UI je vykresleno správně na základě aktuálního stavu. Funkce `renderUI` zpracovává každý stav odpovídajícím způsobem a poskytuje jasný a typově bezpečný způsob správy UI.

Osvědčené Postupy pro Používání Rozlišených Unií

Chcete-li efektivně využívat rozlišené unie ve svých projektech TypeScript, zvažte následující osvědčené postupy:

Pokročilé Techniky

Podmíněné Typy

Podmíněné typy lze kombinovat s rozlišenými uniemi a vytvářet tak ještě výkonnější a flexibilnější stavové automaty. Například můžete použít podmíněné typy k definování různých návratových typů pro funkci na základě aktuálního stavu.


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

Tato funkce používá jednoduchý příkaz `if`, ale mohla by být robustnější pomocí podmíněných typů, aby bylo zajištěno, že bude vždy vrácen konkrétní typ.

Užitečné Typy

Užitečné typy TypeScriptu, jako jsou `Extract` a `Omit`, mohou být užitečné při práci s rozlišenými uniemi. `Extract` vám umožňuje extrahovat konkrétní členy z typu unie na základě podmínky, zatímco `Omit` vám umožňuje odebrat vlastnosti z typu.


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

// Omit the 'message' property from the Error interface
type ErrorWithoutMessage = Omit;

Příklady z Reálného Světa v Různých Odvětvích

Síla rozlišených unií se rozšiřuje do různých odvětví a aplikačních oblastí:

Závěr

Rozlišené unie TypeScriptu poskytují výkonný a typově bezpečný způsob vytváření stavových automatů. Jasným definováním možných stavů a přechodů můžete vytvořit robustnější, udržitelnější a srozumitelnější kód. Kombinace typové bezpečnosti, kontroly vyčerpání a vylepšeného doplňování kódu činí z rozlišených unií neocenitelný nástroj pro každého vývojáře TypeScriptu, který se zabývá složitou správou stavů. Osvojte si rozlišené unie ve svém příštím projektu a zažijte výhody typově bezpečné správy stavů na vlastní kůži. Jak jsme ukázali na různých příkladech od e-commerce po zdravotnictví a od logistiky po vzdělávání, princip typově bezpečné správy stavů prostřednictvím rozlišených unií je univerzálně použitelný.

Ať už vytváříte jednoduchou komponentu UI nebo složitou podnikovou aplikaci, rozlišené unie vám mohou pomoci efektivněji spravovat stav a snížit riziko chyb za běhu. Tak se do toho pusťte a prozkoumejte svět stavových automatů s bezpečným typem s TypeScriptem!

TypeScript Rozlišené Unie: Vytváření stavových automatů s bezpečným typem | MLOG