【React】JavaScriptからTypeScriptに移行する方法

## はじめに
普段、Webサイト制作を行なっておりスキルアップの一環で1年強Reactの勉強をしていますが、最近TypeScriptを勉強し始めたのでアウトプットとして今までに作ったReactアプリのJavaScriptをTypeScriptに移行したので備忘録を兼ねて記事を書こうと思いました。

業務外に全て独学で学んだだけなので間違ってる箇所も多いと思いますが、温かい目で見ていただけると幸いです。

## 1. TypeScriptの依存関係をインストール
まず、TypeScriptと型定義パッケージをインストールします。
```
$ npm install typescript @types/react @types/react-dom
```
開発環境用なら`--save-dev`をつける。

## 2. `tsconfig.json`を作成
ルートディレクトリに`tsconfig.json`を作成します。以下のコマンドで自動生成できます。
```
$ npx tsc --init
```
いくつかの記事を参考に今回は設定を以下のようにしましたが、ここはプロジェクトに合わせて変更すると良い。
```ts:tsconfig.json
{
    "compilerOptions": {
		"target": "ES6",
		"lib": ["DOM", "DOM.Iterable", "ESNext"],
		"jsx": "preserve",
		"module": "ESNext",
		"moduleResolution": "node",
		"resolveJsonModule": true,
		"allowJs": true,
		"noEmit": true,
		"isolatedModules": true,
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true,
		"strict": true,
		"skipLibCheck": true,
	},
	"include": [
		"**/*.ts",
		"**/*.tsx"
	],
	"exclude": [
		"node_modules",
	],
}
```

## 3. `.js`→`.tsx`に拡張子を変更
- Reactコンポーネントが書かれている`.js`ファイルを`.tsx`に変更。
- それ以外の純粋なJavaScriptファイル(Reactを含まないもの)は`.ts`に変更。

【例】
```
src/
├── App.js         → App.tsx
├── index.js       → index.tsx
├── components/
│   └── Weather.js → Weather.tsx
```

## 4. 型を追加する
各ファイルで以下のように型注釈を追加する。

【例】Weather.tsx

修正前
```jsx:Weather.js
import { useState, useEffect } from "react";
import { WeatherList } from "./WeatherList";

export const WeatherData = ({ cityName }) => {

    const [data, setData] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        fetch(`${process.env.REACT_APP_API_URL}/weather/?q=${cityName}&units=metric&appid=${process.env.REACT_APP_API_KEY}`)
        .then(res => res.json())
        .then(result => {
            setData(result);
            setLoading(false);
        });
    }, [cityName]);

    if (loading) {
        return <div></div>;
    }

    return (
        <WeatherList data={data} />
    )
};
```
修正後
```tsx:Weather.tsx
import { useState, useEffect } from "react";
import { WeatherList } from "./WeatherList";

type WeatherDataProps = {
    cityName: string;
}

type WeatherApiResponse = {
	name: string;
	weather: {
		main: string;
		description: string;
		icon: string;
	}[];
	main: {
		temp: number;
		humidity: number;
	};
};

export const WeatherData = ({ cityName }: WeatherDataProps) => {

    const [data, setData] = useState<WeatherApiResponse | null>(null);
    const [loading, setLoading] = useState<boolean>(true);

    useEffect(() => {
        fetch(`${process.env.REACT_APP_API_URL}/weather/?q=${cityName}&units=metric&appid=${process.env.REACT_APP_API_KEY}`)
        .then(res => res.json())
        .then((result: WeatherApiResponse) => {
            setData(result);
            setLoading(false);
        });
    }, [cityName]);

    if (loading || !data) {
        return <div></div>;
    }

    return (
        <WeatherList data={data} />
    )
};
```

## 5. 型の定義ファイルを分ける(任意)
型が増えてきたり、共通で使う型が出てきた場合は、定義ファイルを分けると管理しやすくなる。
```ts:types.ts
export type WeatherApiResponse = {
	name: string;
	weather: {
		main: string;
		description: string;
		icon: string;
	}[];
	main: {
		temp: number;
		humidity: number;
	};
};
```
コンポーネント側では
```tsx:Weather.tsx
import { WeatherApiResponse } from "../types";
const [data, setData] = useState<WeatherApiResponse | null>(null);
```

## 6. エラーを修正する
TypeScriptの型チェックが働き、エディターや`npm run start`で型エラーが表示されるようになるので一つずつ修正する。

## 7. ESLint/Prettierとの連携(任意)
型チェックとコード品質を保つためにESLintやPrettierをTypeScriptに対応させると、より堅牢なコードにできる。今回は導入しなかったので、いつかやってみたい。

## 8. GitHubにPush、そしてデプロイ
エラーが全て解消したらいよいよGitHubにPushしてデプロイして公開です。
問題なく動作することが確認できたら完了です。お疲れ様でした！

## 最後に
正直、まだジェネリクスがどうとかよく分かっていないですが、教材を使ってTypeScriptを勉強しただけだと意味不明だったところが、実際に手を動かしてみると自分の中で腑に落ちる感覚があってTypeScript楽しい！ってなりました。出来上がったコードを見ても安全性のあるコードだなと実感しましたし、これからどんどん使っていきたいなと思いました。