既存コードをTypeScriptに書き換える

### はじめに

前回の記事でlaravelにVite経由で導入したReactにTypeScriptを移行したので、続きで既存コードを書き換えていこうと思います。

TypeScriptの移行の記事↓
https://qiita.com/kuro_maru/items/fcfba1ebe46b4b6f8cfa

### そもそも、なぜTypeScriptを使用するのか？

参考サイト⇨https://www.youtube.com/watch?v=X6haQpKrooM
4:00くらいからの解説がなぜ必要なのかの説明がありわかりやすかったです。

### TypeScriptの基本の型

:::note info
#### プリミティブ型

string ⇨ 文字列
number ⇨ 整数、浮動小数点、正数、負数などの数値
boolean ⇨ true/false

#### 存在しないことを表す型

null ⇨ 値が欠如している
undefined ⇨ 値が割り当てられていない

#### 何でもOKな型

any ⇨ どんな型でも通ってしまう
※できる限り避けたい

#### 関数で使用される型

void ⇨ return文を持たない戻り値
never ⇨ 戻ることがない戻り値
:::

### interfaceとtypeの使い所

:::note info
interface ⇨ オブジェクトを定義する際に使用する、配列要素に使用する際は、sampleInterFace[]のように記述する。
type ⇨ 既存の型を基に、新しい型を作成するために使用する。
（Union型や複雑な型を定義するのに適している）
:::

### 書き換え作業

#### eventの型をどうするか

例えば以下のようなコードがあるとして、

```変更前
// 入力内容の反映
const handleChange = (event) => {
 console.log(event);
 const { name, value } = event.target;
 setScheduleFormData({ ...scheduleFormData, [name]: value});
};
```

eventに何も設定しなかったら自動でany型になるが、それもどうかと思ったので調べてみました。
以下の記事がとてもわかりやすかったです⇩
https://qiita.com/y-suzu/items/9e9a243aaded5952834a

![スクリーンショット 2023-11-26 21.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513569/493c7e6c-97e7-47af-066f-bc579ef96824.png)

console.log()で実際に調べてみました。

```変更後
// 入力内容の反映
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
 console.log(event);
 const { name, value } = event.target;
 setScheduleFormData({ ...scheduleFormData, [name]: value});
};
```

#### 同フォーム内で入力が分かれている場合

```
<label className={ Schedule.schedule__label }>
  要件：
  <input  type="text"
          name="requirement"
          placeholder="内容を入力してください"
          className={ Schedule.schedule__content }
          onChange={ handleChange }
  />
</label>
<label className={ Schedule.schedule__label }>
 メモ：
 <textarea className={ Schedule.schedule__content }
           name="memo"
           onChange={ handleChange }
 >
 </textarea>
</label>
```

このようにinput/textareaで入力が分かれている場合は、両方とも検知対象にするため、以下のようにChangeEventHandlerに渡します。

:::note info
HTMLInputElement | HTMLTextAreaElement
:::


```
// 入力内容の反映
const handleChange: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> = (event) => {
 const { name, value } = event.target;
 setScheduleFormData(prevData => ({
    ...prevData, [name]: value
 }));
};
```

ChangeHandlerはreactのonChange()が持つイベントオブジェクトです。
公式GitHub⇨https://github.com/search?q=repo%3Afacebook%2Freact%20ChangeEventHandler&type=code

:::note alert
上記を記述しましたが今回は、送信対象のフォームデータに型を付けたのでイベントに型は付けていません。
:::

#### レスポンスデータの型

今回、レスポンスデータ全体と中身に型を付けたいことがあり調べるとこのような書き方がありました。

:::note info
以下だと、extendedResponseDataはinitialResponseFormの拡張版となっています。
:::


```
// レスポンスデータ内のformFilterDataの型
export interface initialResponseForm {
  id: number;
  requirement: string;
  memo: string;
  cleated_at: string;
};

// レスポンスデータの型
export interface extendedResponseData extends initialResponseForm {
  formFilterData: [];
  message: string;
  selectedDate: string;
};
```
![スクリーンショット 2023-11-29 1.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513569/1ada54fe-cbc3-7845-d6a9-a0ab4784b608.png)

![スクリーンショット 2023-11-29 1.15.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3513569/ddb2fd67-3a3e-cb1f-8002-6465ba7fa773.png)

#### 今回よく出てきたuseState()

useStateは、値の初期値を設定する際に、型推論をしてくれるが何のデータが入ってくるか分からない場合は明示的に型を指定するほうがいいのかなと色々調べていて感じました。

```
// 指定している型は、上記の型です
  const [responseViewData, setResponseViewData] = useState<extendedResponseData>();
  const [formToFilterData, setFormToFilterData] = useState<initialResponseForm[]>();
```

明らかにデータ型がわかるところには、型を明示的にしませんでした。

```
// 予定作成フォームの状態を取得
const [openForm, setOpenForm] = useState(false);
```

#### 非同期処理の関数の型

```
// 非同期処理の宣言
type passToResponseDataFunc = (data: extendedResponseData) => Promise<void>;

export interface propsFunc {
  passToResponseData: passToResponseDataFunc;
};
```

:::note info
passToResponseDataFuncで、extendedResponseData型を持つdataを引数に受け取り、Promise<void>を返す = つまり、非同期処理の宣言を行い、propsFuncでpassToResponseDataに非同期処理の型を付けています。
:::

戻り値の型にPromise voidを指定しているのは、
```
const passToResponseData: passToResponseDataFunc = async(data) => {
    setResponseViewData(data);
    setOpenForm(!openForm);
};
```
今回の場合だと、return文がないからです。
もし、戻り値がある場合はこのように設定できるそうです。

```
// T にnumberや対象のデータ型が入ります
Promise<T>
```


非同期処理の宣言については、以下の記事が参考になりました。
https://typescript-jp.gitbook.io/deep-dive/type-system/functions

#### propsの型

迷ったのが、React.FCの使用についてです。

```
const ScheduleForm: React.FC<propsFunc> = ({ passToResponseData }) => {
```

:::note info
React.FCとは？
「そのコンポーネントが受け取るPropsの値の型を定義するために使用するもの」だそうで、コンポーネントが受け取るPropsの型や形式が明白になるそうです。
:::

いいとこ尽くしなような気がしましたが、これから開発を続けていく上で、再利用する場面も出てくるかも知れないなと思い、React.FCを使用しなくても定義できるようなので今回は使用はしませんでした。

```
// 定義できました
const ScheduleForm = ({ passToResponseData }: propsFunc) => {
```

意見が参考になった記事⇩
https://qiita.com/islandryu/items/6477ff6a3a9d74a7cc8c

### まとめ

今回、初めはjavascriptで記述したものをtypescriptで型指定するような方法をとりましたが、strictモードのおかげでしっかりエラーが出てくれました。
修正部分に疑問も圧倒的な知識不足を感じたので、引き続きtypescriptで開発を続けていこうと思います。