メインコンテンツへスキップ

React NativeでのTypeScriptの活用

·8分間の読書
Ash Furrow
Artsyのソフトウェアエンジニア

JavaScript! みんな大好きですよね。でも、中にはが好きな人もいます。幸いなことに、JavaScriptにより強力な型を追加するための選択肢はあります。私のお気に入りはTypeScriptですが、React NativeはFlowを標準でサポートしています。どちらを好むかは好みの問題で、それぞれJavaScriptに型の魔法を追加する方法について独自のアプローチを持っています。今日は、React NativeアプリでTypeScriptを使用する方法を見ていきます。

この記事では、MicrosoftのTypeScript-React-Native-Starterリポジトリをガイドとして使用しています。

更新: このブログ記事が書かれて以来、状況はさらに簡単になりました。この記事で説明されているすべての設定は、たった1つのコマンドを実行することで置き換えることができます

npx react-native init MyAwesomeProject --template react-native-template-typescript

ただし、BabelのTypeScriptサポートにはいくつかの制限があります。上記のブログ記事では、それらについて詳しく説明しています。*この記事*で概説されている手順はまだ有効であり、Artsyは本番環境でreact-native-typescript-transformerを使用していますが、React NativeとTypeScriptをすぐに使い始めるための最速の方法は、上記のコマンドを使用することです。必要であれば、いつでも後で切り替えることができます。

いずれにせよ、楽しんでください! 元のブログ記事は以下に続きます。

前提条件

複数の異なるプラットフォームで開発し、複数の異なるタイプのデバイスをターゲットにする可能性があるため、基本的な設定が必要になる場合があります。最初に、TypeScriptを使用せずにプレーンなReact Nativeアプリを実行できることを確認する必要があります。React Native Webサイトの手順に従って開始してください。デバイスまたはエミュレータにデプロイできたら、TypeScript React Nativeアプリを開始する準備が整います。

Node.jsnpmYarnも必要になります。

初期化

通常のReact Nativeプロジェクトのスキャフォールディングを試したら、TypeScriptの追加を開始する準備が整います。早速やってみましょう。

react-native init MyAwesomeProject
cd MyAwesomeProject

TypeScriptの追加

次の手順は、プロジェクトにTypeScriptを追加することです。以下のコマンドは

  • プロジェクトにTypeScriptを追加します
  • プロジェクトにReact Native TypeScript Transformerを追加します
  • 空のTypeScript設定ファイル(次に設定します)を初期化します
  • 空のReact Native TypeScript Transformer設定ファイル(次に設定します)を追加します
  • ReactとReact Nativeの型定義を追加します

それでは、これらを実行してみましょう。

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

tsconfig.jsonファイルには、TypeScriptコンパイラのすべての設定が含まれています。上記のコマンドで作成されたデフォルトはほとんど問題ありませんが、ファイルを開いて次の行のコメントを外してください

{
/* 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. */
}

rn-cli.config.jsには、React Native TypeScript Transformerの設定が含まれています。ファイルを開いて、次を追加してください

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

TypeScriptへの移行

生成されたApp.js__tests_/App.jsファイルをApp.tsxに名前変更します。 index.js.js拡張子を使用する必要があります。すべての新しいファイルは.tsx拡張子(JSXが含まれていない場合は.ts)を使用する必要があります。

ここでアプリを実行しようとすると、object prototype may only be an object or nullのようなエラーが発生します。これは、Reactからのデフォルトエクスポートと、同じ行での名前付きエクスポートのインポートに失敗したことが原因です。 App.tsxを開き、ファイルの先頭にあるインポートを修正します

-import React, { Component } from 'react';
+import React from 'react'
+import { Component } from 'react';

これの一部は、BabelとTypeScriptがCommonJSモジュールと相互運用する方法の違いに関係しています。将来的には、2つは同じ動作で安定します。

この時点で、React Nativeアプリを実行できるはずです。

TypeScriptテストインフラストラクチャの追加

React NativeにはJestが付属しているため、TypeScriptでReact Nativeアプリをテストするには、devDependenciests-jestを追加する必要があります。

yarn add --dev ts-jest

次に、package.jsonを開き、jestフィールドを次のように置き換えます

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

これにより、Jestはts-jestを使用して.tsおよび.tsxファイルを実行するように設定されます。

依存関係型宣言のインストール

TypeScriptで最高のエクスペリエンスを得るには、型チェッカーが依存関係の形状とAPIを理解するようにする必要があります。一部のライブラリは、.d.tsファイル(型宣言/型定義ファイル)とともにパッケージを公開します。これは、基礎となるJavaScriptの形状を記述できます。他のライブラリの場合は、@types/ npmスコープで適切なパッケージを明示的にインストールする必要があります。

たとえば、ここではJest、React、React Native、React Test Rendererの型が必要です。

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

これらの宣言ファイルパッケージは、開発時にのみこれらの依存関係を使用し、実行時には使用しないReact Native *アプリ*であるため、*dev* 依存関係に保存しました。ライブラリをNPMに公開する場合、これらの型依存関係の一部を通常の依存関係として追加する必要がある場合があります。

.d.ts ファイルの取得については、こちらをご覧ください。

より多くのファイルを無視する

ソース管理では、.jest フォルダーを無視する必要があります。 gitを使用している場合は、.gitignore ファイルにエントリを追加するだけです。

# Jest
#
.jest/

チェックポイントとして、ファイルをバージョン管理にコミットすることを検討してください。

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

コンポーネントの追加

アプリにコンポーネントを追加してみましょう。 Hello.tsx コンポーネントを作成しましょう。これは教育的なコンポーネントであり、実際にアプリで記述するものではありませんが、React NativeでTypeScriptを使用する方法を示す重要なものです。

components ディレクトリを作成し、次の例を追加します。

// 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',
},
});

うわー!たくさんありますが、分解してみましょう

  • divspanh1などのHTML要素をレンダリングする代わりに、ViewButtonなどのコンポーネントをレンダリングしています。これらは、異なるプラットフォームで動作するネイティブコンポーネントです。
  • スタイリングは、React Nativeが提供するStyleSheet.create関数を使用して指定されます。 Reactのスタイルシートを使用すると、Flexboxを使用してレイアウトを制御し、CSSに類似した他の構成要素を使用してスタイルを設定できます。

コンポーネントテストの追加

コンポーネントができたので、テストしてみましょう。

テストランナーとしてJestがすでにインストールされています。コンポーネントのスナップショットテストを作成します。スナップショットテストに必要なアドオンを追加しましょう。

yarn add --dev react-addons-test-utils

次に、components ディレクトリに __tests__ フォルダーを作成し、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();
});

テストが初めて実行されると、レンダリングされたコンポーネントのスナップショットが作成され、components/__tests__/__snapshots__/Hello.tsx.snap ファイルに保存されます。コンポーネントを変更すると、スナップショットを更新し、意図しない変更がないか更新を確認する必要があります。 React Nativeコンポーネントのテストの詳細については、こちらをご覧ください。

次のステップ

公式のReactチュートリアルと状態管理ライブラリReduxをご覧ください。これらのリソースは、React Nativeアプリを作成する際に役立ちます。さらに、Web上のReactとReact Nativeの両方をサポートする、TypeScriptで完全に記述されたコンポーネントライブラリであるReactXPもご覧ください。

よりタイプセーフなReact Native開発環境をお楽しみください!