TypeScriptin käyttäminen

TypeScript on suosittu tapa lisätä tyyppimääritteitä JavaScript koodiin. TypeScript tukee JSX:ää ja voit saada täyden React Web tuen lisäämällä @types/react ja @types/react-dom projektiisi.

Asennus

Kaikki tuotantokäyttöön tarkoitetut React frameworkit tarjoavat tuen TypeScriptin käyttöön. Seuraa frameworkin omaa asennusohjetta:

TypeScriptin lisääminen olemassa olevaan React projektiin

Asentaaksesi uusimman version Reactin tyyppimäärittelyistä:

Terminal
npm install @types/react @types/react-dom

Seuraavat compiler-asetukset on oltava asetettuna tsconfig.json tiedostossasi:

  1. dom täytyy olla sisällytettynä lib:ssa (Huomaa: Jos lib vaihtoehtoa ei ole määritelty, dom sisällytetään oletuksena).
  2. jsx:n täytyy olla yksi sallituista vaihtoehdoista. preserve riittää useimmille sovelluksille. If you’re publishing a library, consult the jsx documentation on what value to choose. Jos olet julkaisemassa kirjastoa, tutustu jsx dokumentaatioon mitä arvoa valita.

TypeScript React komponenteissa

Huomaa

Jokainen tiedosto joka sisältää JSX:ää täytyy käyttää .tsx tiedostopäätettä. Tämä on TypeScriptin oma tiedostopääte joka kertoo TypeScriptille että tämä tiedosto sisältää JSX:ää.

TypeScriptin kirjoittaminen Reactin kanssa on hyvin samanlaista kuin JavaScriptin kirjoittaminen Reactin kanssa. Suurin ero on että voit määritellä tyypit komponentin propseille. Nämä tyypit voidaan käyttää oikeellisuuden tarkistamiseen ja sisäisen dokumentaation tarjoamiseen editoreissa.

MyButton komponentin ottaminen Pika-aloitus -oppaasta, voimme lisätä tyypin joka kuvaa title propin painikkeelle:

function MyButton({ title }: { title: string }) {
  return (
    <button>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Tervetuloa sovellukseeni</h1>
      <MyButton title="Olen painike" />
    </div>
  );
}

Huomaa

Nämä hiekkalaatikot tukevat TypeScript koodia, mutta ne eivät aja tyyppitarkistinta. Tämä tarkoittaa että voit muokata TypeScript hiekkalaatikoita oppiaksesi, mutta et saa mitään tyyppivirheitä tai varoituksia. Saadaksesi tyyppitarkistuksen, voit käyttää TypeScript Playground tai käyttää enemmän ominaisuuksia sisältävää hiekkalaatikkoa.

Tämä sisäinen syntaksi on yksinkertaisin tapa määritellä tyypit komponentille, mutta kun sinulla on muutama kenttä kuvattavana, se voi muuttua hankalaksi. Sen sijaan voit käyttää interface tai type kuvaamaan komponentin propseja:

interface MyButtonProps {
  /** Teksti jota näytetään painikkeen sisällä */
  title: string;
  /** Voiko painiketta käyttää */
  disabled: boolean;
}

function MyButton({ title, disabled }: MyButtonProps) {
  return (
    <button disabled={disabled}>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Tervetuloa sovellukseeni</h1>
      <MyButton title="Olen käytöstä poistettu painike" disabled={true}/>
    </div>
  );
}

Tyyppi joka kuvaa komponentin propseja voi olla yhtä yksinkertainen tai monimutkainen kuin tarvitset, mutta niiden tulisi olla objektityyppi joka on kuvattu joko type tai interface avulla. Voit oppia kuinka TypeScript kuvaa objekteja Object Types -oppaasta, mutta saatat olla kiinnostunut käyttämään Union Types kuvaamaan propsia joka voi olla yksi monista eri tyypeistä ja Creating Types from Types -opas monimutkaisempiin käyttötapauksiin.

Hookki-esimerkkejä

Tyyppimäärittelyt @types/react paketissa sisältävät tyypit sisäänrakennetuille hookkeille, joten voit käyttää niitä komponenteissasi ilman lisäasetuksia. Ne on rakennettu ottamaan huomioon koodi jonka kirjoitat komponenttiisi, joten saat pääteltyjä tyyppejä usein ja sinun ei pitäisi tarvita käsitellä yksityiskohtia tyypittämisestä.

Kuitenkin, voimme katsoa muutamia esimerkkejä kuinka tarjota tyyppejä hookkeille.

useState

useState hookki käyttää uuddelleen arvoa joka annetaan alustavaksi tilaksi määrittääkseen minkä tyyppinen arvo on kyseessä. Esimerkiksi:

// Päättele arvoksi "boolean":ksi
const [enabled, setEnabled] = useState(false);

Päättelee enabled tyypiksi boolean ja setEnabled on funktio joka hyväksyy joko boolean argumentin tai funktion joka palauttaa boolean arvon. Jos haluat määrittää tyypin tilalle, voit tehdä sen antamalla tyypin argumentin useState kutsulle:

// Eksplisiittisesti aseta tyyppi "boolean":ksi
const [enabled, setEnabled] = useState<boolean>(false);

Tämä ei ole kovin hyödyllistä tässä tapauksessa, mutta yleinen tapaus jossa haluat määrittää tyypin on kun sinulla on union tyyppi. Esimerkiksi, status voi olla yksi monista eri merkkijonoista:

type Status = "idle" | "loading" | "success" | "error";

const [status, setStatus] = useState<Status>("idle");

Tai, kuten suositellaan Tilarakenteiden periaatteissa, voit ryhmitellä liittyvän tilan objektiksi ja kuvailla eri mahdollisuudet objektityypeillä:

type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success', data: any }
| { status: 'error', error: Error };

const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' });

useReducer

useReducer hookki on monimutkaisempi hookki joka ottaa reduktorifunktion ja alustavan tilan. Tyypit reducer funktiolle päätellään alustavasta tilasta. Voit valinnaisesti antaa tyypin argumentin useReducer kutsulle antaaksesi tyypin tilalle, mutta on usein parempi asettaa tyyppi alustavalle tilalle:

import {useReducer} from 'react';

interface State {
   count: number 
};

type CounterAction =
  | { type: "reset" }
  | { type: "setCount"; value: State["count"] }

const initialState: State = { count: 0 };

function stateReducer(state: State, action: CounterAction): State {
  switch (action.type) {
    case "reset":
      return initialState;
    case "setCount":
      return { ...state, count: action.value };
    default:
      throw new Error("Unknown action");
  }
}

export default function App() {
  const [state, dispatch] = useReducer(stateReducer, initialState);

  const addFive = () => dispatch({ type: "setCount", value: state.count + 5 });
  const reset = () => dispatch({ type: "reset" });

  return (
    <div>
      <h1>Tervetuloa laskuriini</h1>

      <p>Laskuri: {state.count}</p>
      <button onClick={addFive}>Lisää 5</button>
      <button onClick={reset}>Nollaa</button>
    </div>
  );
}

Käytämme TypeScriptiä muutamassa keskeisessä paikassa:

  • interface State kuvaa reduktorin tilan muodon.
  • type CounterAction kuvaa eri toimintoja jotka voidaan lähettää reduktorille.
  • const initialState: State tarjoaa tyypin alustavalle tilalle, ja myös tyypin jota useReducer käyttää oletuksena.
  • stateReducer(state: State, action: CounterAction): State asettaa tyypit reduktorifunktion argumenteille ja palautusarvolle.

Eksplisiittisempi vaihtoehto tyypin asettamiseen initialState:lle on antaa tyyppi argumentti useReducer:lle:

import { stateReducer, State } from './your-reducer-implementation';

const initialState = { count: 0 };

export default function App() {
const [state, dispatch] = useReducer<State>(stateReducer, initialState);
}

useContext

useContext hookki on tekniikka datan välittämiseen komponenttipuun läpi ilman että tarvitsee välittää propseja komponenttien läpi. Sitä käytetään luomalla tarjoaja komponentti ja usein luomalla hookki arvon käyttöön lapsikomponentissa.

Kontekstin tarjoaman arvon tyyppi päätellään arvosta joka annetaan createContext kutsulle:

import { createContext, useContext, useState } from 'react';

type Theme = "light" | "dark" | "system";
const ThemeContext = createContext<Theme>("system");

const useGetTheme = () => useContext(ThemeContext);

export default function MyApp() {
  const [theme, setTheme] = useState<Theme>('light');

  return (
    <ThemeContext.Provider value={theme}>
      <MyComponent />
    </ThemeContext.Provider>
  )
}

function MyComponent() {
  const theme = useGetTheme();

  return (
    <div>
      <p>Nykyinen teema: {theme}</p>
    </div>
  )
}

Tämä tekniikka toimii kun sinulla on oletusarvo joka on järkevä - mutta on tapauksia jolloin sitä ei ole, ja näissä tapauksissa null voi tuntua järkevältä oletusarvolta. Kuitenkin, jotta tyyppijärjestelmä ymmärtäisi koodisi, sinun täytyy eksplisiittisesti asettaa ContextShape | null createContext:lle.

Tämä aiheuttaa ongelman jossa sinun täytyy eliminoida | null tyyppi kontekstin kuluttajilta. Suosituksemme on että hookki tekee runtime tarkistuksen sen olemassaolosta ja heittää virheen kun sitä ei ole:

import { createContext, useContext, useState, useMemo } from 'react';

// Tämä on yksinkertaisempi esimerkki, mutta voit kuvitella monimutkaisemman olion tässä
type ComplexObject = {
kind: string
};

// Konteksti luodaan `| null` tyypillä, jotta oletusarvo heijastuu tarkasti.
const Context = createContext<ComplexObject | null>(null);

// `| null` tullaan poistamaan tarkistuksen kautta hookissa.
const useGetComplexObject = () => {
const object = useContext(Context);
if (!object) { throw new Error("useGetComplexObject must be used within a Provider") }
return object;
}

export default function MyApp() {
const object = useMemo(() => ({ kind: "complex" }), []);

return (
<Context.Provider value={object}>
<MyComponent />
</Context.Provider>
)
}

function MyComponent() {
const object = useGetComplexObject();

return (
<div>
<p>Nykyinen olio: {object.kind}</p>
</div>
)
}

useMemo

useMemo hookki luo/uudelleen käyttää muistettua arvoa funktiokutsusta, ajamalla funktiota uudelleen vain kun riippuvuudet jotka on annettu toisena parametrina muuttuvat. Kutsun tulosta päätellään palautusarvosta funktiossa ensimmäisenä parametrina. Voit olla eksplisiittisempi antamalla tyypin argumentin hookille.

// visibleTodos:n tyyppi päätellään filterTodos:n palautusarvosta
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);

useCallback

useCallback tarjoaa vakaan viitteen funktioon niin kauan kun riippuvuudet jotka on annettu toisena parametrina pysyvät samana. Kuten useMemo, funktion tyyppi päätellään funktiosta palautusarvona ensimmäisenä parametrina, ja voit olla eksplisiittisempi antamalla tyypin argumentin hookille.

const handleClick = useCallback(() => {
// ...
}, [todos]);

Kun työskentelet TypeScriptin strict-moodissa useCallback vaatii lisäämään tyypit parametreille callbackissasi. Tämä johtuu siitä että callbackin tyyppi päätellään funktion palautusarvosta, ja ilman parametreja tyyppiä ei voida ymmärtää täysin.

Riippuen koodityylistäsi, voit käyttää *EventHandler funktioita Reactin tyypeistä tarjotaksesi tyypin tapahtumankäsittelijälle samaan aikaan kun määrittelet callbackin:

import { useState, useCallback } from 'react';

export default function Form() {
const [value, setValue] = useState("Change me");

const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {
setValue(event.currentTarget.value);
}, [setValue])

return (
<>
<input value={value} onChange={handleChange} />
<p>Value: {value}</p>
</>
);
}

Hyödyllisiä tyyppejä

@types/react paketissa on melko laaja joukko tyyppejä, on hyvä lukea ne kun tunnet olosi mukavaksi kuinka React ja TypeScript toimivat yhdessä. Voit löytää ne Reactin kansiossa DefinitelyTypedissä. Käydään läpi muutamia yleisimpiä tyyppejä tässä.

DOM tapahtumat

Kun työskentelet DOM tapahtumien kanssa Reactissa, tapahtuman tyyppi voidaan usein päätellä tapahtumankäsittelijästä. Kuitenkin, kun haluat eristää funktion joka annetaan tapahtumankäsittelijälle, sinun täytyy eksplisiittisesti asettaa tapahtuman tyyppi.

import { useState } from 'react';

export default function Form() {
  const [value, setValue] = useState("Change me");

  function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
    setValue(event.currentTarget.value);
  }

  return (
    <>
      <input value={value} onChange={handleChange} />
      <p>Arvo: {value}</p>
    </>
  );
}

On monia eri tapahtumia, joita Reactin tyypit tarjoaa - täydellinen lista löytyy täältä joka perustuu suosituimpiin tapahtumiin DOM:issa.

Kun etsit tyyppiä, voit ensin katsoa hover tiedot tapahtumankäsittelijälle jota käytät, joka näyttää tapahtuman tyypin.

Jos sinun täytyy käyttää tapahtumaa jota ei ole tässä listassa, voit käyttää React.SyntheticEvent tyyppiä, joka on kaikkien tapahtumien perustyypi.

Children

On kaksi yleistä tapaa kuvailla komponentin lapsia. Ensimmäinen on käyttää React.ReactNode tyyppiä, joka on unioni kaikista mahdollisista tyypeistä jotka voidaan antaa lapsina JSX:ssä:

interface ModalRendererProps {
title: string;
children: React.ReactNode;
}

Tämä on hyvin laaja määritelmä lapsille. Toinen tapa on käyttää React.ReactElement tyyppiä, joka on vain JSX elementtejä eikä JavaScript primitiivejä kuten merkkijonoja tai numeroita:

interface ModalRendererProps {
title: string;
children: React.ReactElement;
}

Huomaa, että et voi käyttää TypeScriptiä kuvaamaan että lapset ovat tietyn tyyppisiä JSX elementtejä, joten et voi käyttää tyyppijärjestelmää kuvaamaan komponenttia joka hyväksyy vain <li> lapsia.

Näet esimerkin sekä React.ReactNode:sta että React.ReactElement:sta tyyppitarkistuksella tässä TypeScript hiekkalaatikossa.

Tyylipropsit

Kun käytät inline-tyylejä Reactissa, voit käyttää React.CSSProperties kuvaamaan objektia joka annetaan style propille. Tämä tyyppi on unioni kaikista mahdollisista CSS ominaisuuksista, ja on hyvä tapa varmistaa että annat oikeellisia CSS ominaisuuksia style propille, ja saadaksesi automaattisen täydennyksen editoriisi.

interface MyComponentProps {
style: React.CSSProperties;
}

Osaamisen laajentaminen

Tämä opas on käsitellyt TypeScriptin käyttöä Reactin kanssa, mutta on paljon enemmän opittavaa. Yksittäiset API sivut dokumentaatiossa voivat sisältää syvällisempää dokumentaatiota kuinka käyttää niitä TypeScriptin kanssa.

Suosittelemme seuraavia resursseja: