React Academy · Oppitunti

Diskriminoidut unionit komponenttivarianteille

Mallintakaa varianttipropsit diskriminoiduilla unioneilla, jotta TypeScript valvoo kelvollisia propsiyhdistelmiä.

Oppitunti 1/413 vaihetta

Diskriminoidut unionit komponenttivarianteille on ilmainen React Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu React Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. React Academy-kurssilla on yhteensä 4 oppituntia.

Variant-propsien ongelma

Komponentilla, jossa on eri tiloja varten valinnaisia propseja, kuten painikkeella, joka voi olla joko linkki tai painike, voi olla virheellisiä prop-yhdistelmiä. TypeScript ei pysty havaitsemaan niitä ilman discriminated union -tyyppejä.

Mikä on discriminated union?

Discriminated union on tyyppien unioni, jonka jäsenillä on yhteinen literaalityyppinen kenttä (discriminant). TypeScript rajaa tyypin tämän kentän arvon perusteella.

type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  if (shape.kind === 'circle') return Math.PI * shape.radius ** 2;
  return shape.width * shape.height; // TS knows width/height exist here
}

Button- ja Link-variantti

Mallinna polymorfinen komponentti as- tai variant-kentän discriminated unionilla, jotta kunkin tapauksen oikeat propsit voidaan varmistaa.

type ButtonProps =
  | { as: 'button'; onClick: () => void; disabled?: boolean; children: React.ReactNode }
  | { as: 'a'; href: string; target?: string; children: React.ReactNode };

function ActionButton(props: ButtonProps) {
  if (props.as === 'button') {
    return <button onClick={props.onClick} disabled={props.disabled}>{props.children}</button>;
  }
  return <a href={props.href} target={props.target}>{props.children}</a>;
}

Alert-komponentin variantit

Mallinna Alert siten, että jokainen severity-tyyppi edellyttää erilaisia tietoja.

type AlertProps =
  | { type: 'success'; message: string }
  | { type: 'error'; message: string; onRetry: () => void }
  | { type: 'warning'; message: string; details?: string };

function Alert(props: AlertProps) {
  if (props.type === 'error') {
    return (
      <div className="alert error">
        <p>{props.message}</p>
        <button onClick={props.onRetry}>Retry</button>
      </div>
    );
  }
  return <div className={`alert ${props.type}`}>{props.message}</div>;
}

Tyyppien rajaaminen tapahtumankäsittelijöissä

Discriminated unionit toimivat myös tapahtumavetoisen datan kanssa – ne sopivat erinomaisesti tilakoneisiin tai action-pohjaiseen tilanhallintaan.

type LoadingState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };

function DataView<T>({ state }: { state: LoadingState<T> }) {
  if (state.status === 'loading') return <Spinner />;
  if (state.status === 'error') return <p>{state.error.message}</p>;
  if (state.status === 'success') return <pre>{JSON.stringify(state.data)}</pre>;
  return null;
}

Kattavuustarkistukset never-tyypillä

Lisää oletushaaraan never-tarkistus, jotta TypeScript ilmoittaa virheestä, jos unioniin lisätään uusi jäsen mutta sitä ei käsitellä.

function assertNever(x: never): never {
  throw new Error('Unhandled case: ' + x);
}

function renderIcon(type: AlertProps['type']) {
  switch (type) {
    case 'success': return <CheckIcon />;
    case 'error': return <XIcon />;
    case 'warning': return <WarnIcon />;
    default: return assertNever(type); // TS error if a case is missing
  }
}

Discriminated unionit API-vastauksille

Mallinna API-vastausten rakenteet discriminated union -tyyppeinä, jotta kutsuja voi käsitellä onnistumis- ja virhepolut ilman tyyppimuunnoksia.

type ApiResult<T> =
  | { ok: true; data: T }
  | { ok: false; error: string; code: number };

async function fetchUser(id: string): Promise<ApiResult<User>> {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) return { ok: false, error: 'Not found', code: res.status };
  return { ok: true, data: await res.json() };
}

Type guardit tyyppien rajaamiseen

Käytä mukautettuja type guard -tarkistuksia unionien rajaamiseen monimutkaisemmissa tilanteissa, joissa discriminant ei ole yksinkertainen yhtäsuuruustarkistus.

function isSuccess<T>(result: ApiResult<T>): result is { ok: true; data: T } {
  return result.ok === true;
}

const result = await fetchUser('1');
if (isSuccess(result)) {
  console.log(result.data.name); // TS knows data exists
}

Valinnaisten propsien sekamelskan välttäminen

Ilman discriminated union -tyyppejä komponentteihin kertyy valinnaisia propseja, jotka ovat sallittuja vain tietyissä yhdistelmissä – lopputulos on sekava ja tyypittämätön. Discriminated unionit poistavat mahdottomat tilat.

// Bad: optional prop soup — invalid combos allowed:
interface BadProps {
  href?: string;
  onClick?: () => void;
  disabled?: boolean;
}

// Good: only valid combos via discriminated union:
type GoodProps =
  | { as: 'a'; href: string }
  | { as: 'button'; onClick: () => void; disabled?: boolean };

Unionien koostaminen

Lisää unionin kaikille jäsenille yhteiset propsit käyttämällä &-operaattoria (intersection).

type BaseProps = { className?: string; children: React.ReactNode };

type ButtonVariant =
  | (BaseProps & { variant: 'primary'; onClick: () => void })
  | (BaseProps & { variant: 'link'; href: string });

Erottelu ajonaikana

React käyttää discriminant-kenttää ajonaikana oikean käyttöliittymän renderöintiin. TypeScript käyttää sitä käännösaikana oikean prop-käytön varmistamiseen. Molemmat tasot ovat suojattuja.

Pikatarkistus

Mikä on discriminant discriminated unionissa?

Kertaus

Discriminated unionit mallintavat komponentteja, joilla on toisensa poissulkevat prop-joukot ja yhteinen literaalityyppinen discriminant-kenttä. Käytä never-tyyppiä oletushaarassa kattavuustarkistuksiin. Ne poistavat valinnaisten propsien sallimat virheelliset prop-yhdistelmät ja tekevät komponenteista itsensä dokumentoivia ja tyyppiturvallisia.

Aloita maksutta

Opi React tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
88
Oppitunnit
324

Usein kysytyt kysymykset

Onko oppitunti ”Diskriminoidut unionit komponenttivarianteille” ilmainen?

Kyllä – oppitunnin ”Diskriminoidut unionit komponenttivarianteille” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko React Academy-kurssin, päivitä CoddyKit PROhon. React Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Diskriminoidut unionit komponenttivarianteille”?

Mallintakaa varianttipropsit diskriminoiduilla unioneilla, jotta TypeScript valvoo kelvollisia propsiyhdistelmiä. Harjoittelet React Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni React Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin React Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Diskriminoidut unionit komponenttivarianteille”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä React Academy-oppitunnilla?

Kyllä. Jokainen React Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Diskriminoidut unionit komponenttivarianteille
  2. Ehdolliset ja mappautuvat tyypit Reactissa
  3. Polymorfiset komponentit 'as'-propilla
  4. Tyyppiturvalliset lomakkeet ja API-vastaussopimukset
← Takaisin: React Academy