Korzystanie z TypeScript w React Native
Ta strona została przetłumaczona przez PageTurner AI (beta). Nie jest oficjalnie zatwierdzona przez projekt. Znalazłeś błąd? Zgłoś problem →
JavaScript! Wszyscy go kochamy. Ale niektórzy z nas uwielbiają także typy. Na szczęście istnieją rozwiązania pozwalające dodać silniejsze typowanie do JavaScript. Moim ulubionym jest TypeScript, ale React Native natywnie wspiera Flow. Wybór między nimi zależy od preferencji – każde podejście inaczej dodaje magię typów do JavaScript. Dzisiaj przyjrzymy się, jak używać TypeScript w aplikacjach React Native.
Ten wpis korzysta z repozytorium Microsoftu TypeScript-React-Native-Starter jako przewodnika.
Aktualizacja: Od czasu powstania tego wpisu proces stał się jeszcze prostszy. Możesz zastąpić całą konfigurację opisaną w tym artykule, wykonując jedno polecenie:
npx react-native init MyAwesomeProject --template react-native-template-typescript
Istnieją jednak pewne ograniczenia w obsłudze TypeScript przez Babel, które szczegółowo omówiono w powyższym artykule. Kroki opisane w tym wpisie nadal działają, a Artsy nadal używa react-native-typescript-transformer w produkcji, ale najszybszym sposobem na rozpoczęcie pracy z React Native i TypeScript jest użycie powyższego polecenia. Zawsze możesz przełączyć się później, jeśli zajdzie taka potrzeba.
W każdym razie – dobrej zabawy! Oryginalny wpis blogowy kontynuujemy poniżej.
Wymagania wstępne
Ponieważ możesz rozwijać aplikacje na różnych platformach dla różnych typów urządzeń, podstawowa konfiguracja może być złożona. Najpierw upewnij się, że potrafisz uruchomić zwykłą aplikację React Native bez TypeScript. Postępuj zgodnie z instrukcjami na stronie React Native, aby rozpocząć. Gdy uda ci się wdrożyć aplikację na urządzeniu lub emulatorze, będziesz gotowy do stworzenia aplikacji React Native z TypeScript.
Będziesz także potrzebować Node.js, npm i Yarn.
Inicjalizacja
Gdy już spróbujesz stworzyć szkielet zwykłego projektu React Native, będziesz gotowy, aby dodać TypeScript. Zróbmy to teraz.
react-native init MyAwesomeProject
cd MyAwesomeProject
Dodawanie TypeScript
Następnym krokiem jest dodanie TypeScript do projektu. Poniższe polecenia:
-
dodadzą TypeScript do twojego projektu
-
dodadzą React Native TypeScript Transformer do projektu
-
zainicjują pusty plik konfiguracyjny TypeScript, który skonfigurujemy później
-
dodadzą pusty plik konfiguracyjny React Native TypeScript Transformer, który skonfigurujemy później
-
dodadzą definicje typów dla React i React Native
OK, uruchommy te polecenia.
yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native
Plik tsconfig.json zawiera wszystkie ustawienia kompilatora TypeScript. Domyślne wartości utworzone przez powyższe polecenie są w większości poprawne, ale otwórz plik i odkomentuj następującą linię:
{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}
Plik rn-cli.config.js zawiera ustawienia dla React Native TypeScript Transformer. Otwórz go i dodaj następujący kod:
module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};
Migracja do TypeScript
Zmień nazwy wygenerowanych plików App.js i __tests_/App.js na App.tsx. Plik index.js musi zachować rozszerzenie .js. Wszystkie nowe pliki powinny używać rozszerzenia .tsx (lub .ts, jeśli plik nie zawiera JSX).
Gdybyś spróbował teraz uruchomić aplikację, otrzymałbyś błąd podobny do object prototype may only be an object or null. Jest to spowodowane niepowodzeniem w zaimportowaniu domyślnego eksportu z React oraz nazwanego eksportu w tej samej linii. Otwórz plik App.tsx i zmodyfikuj import na początku pliku:
-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';
Część tego problemu wynika z różnic w sposobie współdziałania Babela i TypeScripta z modułami CommonJS. W przyszłości oba narzędzia ustabilizują się pod kątem tego samego zachowania.
W tym momencie powinieneś być w stanie uruchomić aplikację React Native.
Dodawanie infrastruktury testowej TypeScript
React Native dostarczany jest z Jest, więc aby testować aplikację React Native z TypeScript, dodamy ts-jest do naszych devDependencies.
yarn add --dev ts-jest
Następnie otworzymy nasz package.json i zastąpimy pole jest następującą konfiguracją:
{
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
}
}
To skonfiguruje Jesta do uruchamiania plików .ts i .tsx za pomocą ts-jest.
Instalowanie deklaracji typów zależności
Aby uzyskać najlepsze doświadczenia w TypeScript, potrzebujemy, aby sprawdzanie typów rozumiało strukturę i API naszych zależności. Niektóre biblioteki publikują swoje pakiety z plikami .d.ts (deklaracje typów/definicje typów), które opisują strukturę podstawowego JavaScriptu. Dla innych bibliotek musimy jawnie zainstalować odpowiedni pakiet z zakresu npm @types/.
Na przykład będziemy potrzebować typów dla Jesta, Reacta, React Native oraz React Test Renderer.
yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer
Zapisaliśmy te pakiety deklaracji jako zależności dev, ponieważ jest to aplikacja React Native używająca tych zależności wyłącznie podczas rozwoju, a nie w czasie działania. Gdybyśmy publikowali bibliotekę na NPM, musielibyśmy dodać niektóre z tych zależności typów jako zwykłe zależności.
Więcej o uzyskiwaniu plików .d.ts możesz przeczytać tutaj.
Ignorowanie dodatkowych plików
W systemie kontroli wersji warto zignorować folder .jest. Jeśli używasz gita, możesz dodać wpisy do pliku .gitignore.
# Jest
#
.jest/
Jako punkt kontrolny warto zatwierdzić pliki w systemie kontroli wersji.
git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."
Dodawanie komponentu
Dodajmy komponent do naszej aplikacji. Stwórzmy komponent Hello.tsx. Jest to komponent dydaktyczny - nie coś, co napisałbyś w rzeczywistej aplikacji, ale przykład pokazujący nietrywialne użycie TypeScript w React Native.
Utwórz katalog components i dodaj następujący przykład:
// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';
export interface Props {
name: string;
enthusiasmLevel?: number;
}
interface State {
enthusiasmLevel: number;
}
export class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
if ((props.enthusiasmLevel || 0) <= 0) {
throw new Error(
'You could be a little more enthusiastic. :D',
);
}
this.state = {
enthusiasmLevel: props.enthusiasmLevel || 1,
};
}
onIncrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel + 1,
});
onDecrement = () =>
this.setState({
enthusiasmLevel: this.state.enthusiasmLevel - 1,
});
getExclamationMarks = (numChars: number) =>
Array(numChars + 1).join('!');
render() {
return (
<View style={styles.root}>
<Text style={styles.greeting}>
Hello{' '}
{this.props.name +
this.getExclamationMarks(this.state.enthusiasmLevel)}
</Text>
<View style={styles.buttons}>
<View style={styles.button}>
<Button
title="-"
onPress={this.onDecrement}
accessibilityLabel="decrement"
color="red"
/>
</View>
<View style={styles.button}>
<Button
title="+"
onPress={this.onIncrement}
accessibilityLabel="increment"
color="blue"
/>
</View>
</View>
</View>
);
}
}
// styles
const styles = StyleSheet.create({
root: {
alignItems: 'center',
alignSelf: 'center',
},
buttons: {
flexDirection: 'row',
minHeight: 70,
alignItems: 'stretch',
alignSelf: 'center',
borderWidth: 5,
},
button: {
flex: 1,
paddingVertical: 0,
},
greeting: {
color: '#999',
fontWeight: 'bold',
},
});
Wow! To sporo, ale przeanalizujmy to:
-
Zamiast renderować elementy HTML jak
div,span,h1itd., renderujemy komponenty takie jakViewiButton. Są to natywne komponenty działające na różnych platformach. -
Stylowanie określamy za pomocą funkcji
StyleSheet.createdostarczonej przez React Native. Arkusze stylów React pozwalają kontrolować układ przy użyciu Flexboxa i stylizować przy użyciu konstrukcji podobnych do CSS.
Dodawanie testu komponentu
Skoro mamy już komponent, przetestujmy go.
Mamy już zainstalowanego Jesta jako runner testów. Będziemy pisać testy snapshotów dla naszych komponentów, więc dodajmy wymagane rozszerzenie do testów snapshotów:
yarn add --dev react-addons-test-utils
Teraz utwórz folder __tests__ w katalogu components i dodaj test dla Hello.tsx:
// components/__tests__/Hello.tsx
import React from 'react';
import renderer from 'react-test-renderer';
import {Hello} from '../Hello';
it('renders correctly with defaults', () => {
const button = renderer
.create(<Hello name="World" enthusiasmLevel={1} />)
.toJSON();
expect(button).toMatchSnapshot();
});
Podczas pierwszego uruchomienia testu zostanie utworzony migawkowy zapis wyrenderowanego komponentu, który zostanie zapisany w pliku components/__tests__/__snapshots__/Hello.tsx.snap. Po wprowadzeniu zmian w komponencie konieczne będzie zaktualizowanie migawek i przejrzenie ich pod kątem nieoczekiwanych zmian. Więcej o testowaniu komponentów React Native można przeczytać tutaj.
Kolejne kroki
Zapoznaj się z oficjalnym samouczkiem React oraz biblioteką do zarządzania stanem Redux. Te zasoby mogą okazać się pomocne podczas tworzenia aplikacji React Native. Dodatkowo warto przyjrzeć się bibliotece komponentów ReactXP, napisanej w całości w TypeScript i obsługującej zarówno React na webie, jak i React Native.
Powodzenia w bardziej bezpiecznym typowo środowisku programistycznym React Native!