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.
Tulet oppimaan
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ä:
Seuraavat compiler-asetukset on oltava asetettuna tsconfig.json
tiedostossasi:
dom
täytyy olla sisällytettynälib
:ssa (Huomaa: Joslib
vaihtoehtoa ei ole määritelty,dom
sisällytetään oletuksena).jsx
:n täytyy olla yksi sallituista vaihtoehdoista.preserve
riittää useimmille sovelluksille. If you’re publishing a library, consult thejsx
documentation on what value to choose. Jos olet julkaisemassa kirjastoa, tutustujsx
dokumentaatioon mitä arvoa valita.
TypeScript React komponenteissa
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> ); }
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 jotauseReducer
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:
-
The TypeScript handbook on virallinen dokumentaatio TypeScriptille, ja kattaa suurimman osan tärkeimmistä ominaisuuksista.
-
The TypeScript release notes kattaa jokaisen uuden ominaisuuden syvällisesti.
-
React TypeScript Cheatsheet on yhteisön ylläpitämä lunttilappu TypeScriptin käyttöön Reactin kanssa, kattaa paljon hyödyllisiä reunoja ja tarjoaa enemmän syvyyttä kuin tämä dokumentti.
-
TypeScript Community Discord on hyvä paikka kysyä kysymyksiä ja saada apua TypeScriptin ja Reactin ongelmiin.