（Reactにおける）はじめてのTypeScript

使用主言語をJavaScriptからTypeScriptへ転換しようと試みている、そのための大雑把な備忘録リスト。

（なおAngular version7, 8でTypeScriptを書いていたが、Angularはすべてクラス型コンポーネントだったしやはりReactとは違いが色々ありすぎでReact系をTypeScriptで…となると当時の知識は使えない:disappointed_relieved:）

## 準備編
#### TypeScriptインストールコマンド
```cmd
npm install typescript @types/node @types/react @types/react-dom
```

react-router-domをインストールしていたらさらに
```cmd
npm install @types/react-router-dom
```

#### tsconfig.json作成コマンド

```cmd
npx tsc --init
```

#### スタンダードなtsconfig.json

```json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}
```

<br />

## JavaScriptとの比較編

#### デフォルトのindex.jsファイルをTypeScriptにする（index.js → index.tsx）
- JavaScript
```js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);
```
- TypeScript
```ts
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
    <App />
);
```

:::note
`as HTMLElement`を追加
::::




#### ステート変数宣言
- JavaScript
```jsx
const [loading, setLoading] = useState(false);
const [city, setCity] = useState("");
```

- TypeScript
```tsx
const [loading, setLoading] = useState<boolean>(false);
const [city, setCity] = useState<string>("");
```

#### ステート変数宣言（複数をまとめる形式）
- JavaScript
```jsx
  const [results, setResults] = useState({
    country: "",
    cityName: "",
    temperature: 0,
    conditionText: "",
  })
```

- TypeScript
```tsx
type ResultsStateType = {
  country: string;
  cityName: string;
  temperature: number;
  conditionText: string;
}

const [results, setResults] = useState<ResultsStateType>({
  country: "",
  cityName: "",
  temperature: 0,
  conditionText: "",
  icon: "",
})
```
:::note
`type`で型定義宣言。`ResultsStateType`は任意の名前。`ResultsStateType`でいくつかのステート変数をまとめて型定義している.
:::

#### ステート変数宣言（配列形式）
- JavaScript
```js
const [allCountriesData, setAllCountriesData] = useState([])
```

- TypeScript
```ts
type AllCountryDataType = {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}

const [allCountriesData, setAllCountriesData] = useState<AllCountriesDataType>([{
   Country: "",
   NewConfirmed: 0,
   TotalConfirmed: 0,
}])
```

:::note
JavaScriptならカラの配列である、というだけで何も文句は言われない。TypeScriptでは具体的にどんな要素データが配列に入るか、まずは明示する必要がある。
```typescript
const [allCountriesData, setAllCountriesData] = useState([{
    Country: "",
    NewConfirmed: 0,
    TotalConfirmed: 0,
}])
```

その上で、以下のように`type`で型定義する。
```ts
type AllCountryDataType = {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}
```
:::

#### ステート変数宣言（配列形式）― `type`の代わりに`interface`を使う場合

- TypeScript
```ts
interface SingleCountriesDataType {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}
interface AllCountriesDataTypeArray extends Array<SingleCountriesDataType>{}

  const [allCountriesData, setAllCountriesData] = useState<AllCountriesDataTypeArray>([{
    Country: "",
    NewConfirmed: 0,
    TotalConfirmed: 0,
  }]) 
```

:::note
ひとつ目の`interface`で定義しているのは一個の{}データなので`SingleCountriesDataType`という名前にしている（分かりやすくするためだけ）。別に`AllCountriesDataType`でも`CountriesDataType`でも良い。

そして
`AllCountriesDataTypeArray extends Array<SingleCountriesDataType>{}`
によって、`AllCountriesDataTypeArray`が`SingleCountriesDataType`を拡張した配列であることを明示している。

最後にくっついている`{}`はおまじない的なオマケ。
:::



#### 関数に渡されるFormのイベント`e`
- JavaScript
```js
  const getInfo = (e) => {
      e.preventDefault();
// ・・・省略・・・
  }
```

- TypeScript
```ts
  const getInfo = (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
// ・・・省略・・・
  }
```

:::note
フォームイベント`e`は、Reactが定義している型`React.FormEvent<HTMLFormElement>`となる
:::

#### propsに渡されたステート関数（ここでは`props.setCity`）
- JavaScript

（propsを渡してる側のコンポーネント）
```js
const [city, setCity] = useState("");
// ...
<Form setCity={setCity} getInfo={getInfo} />
```

（propsを渡されてる側のコンポーネント）

```js
const Form = (props) => {
    return (
        <form>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Submit</button>
        </form>
    );
};
```

- TypeScript

（propsを渡してる側のコンポーネント）
```ts
const [city, setCity] = useState<string>("");
// ...
<Form setCity={setCity} getInfo={getInfo} />
```
（propsを渡されてる側のコンポーネント）
```ts
type FormPropsType = {
    city: string;
    setCity: React.Dispatch<React.SetStateAction<string>>;
}

const Form = (props: FormPropsType) => {
    return (
        <form>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Submit</button>
        </form>

    );
};
```

:::note
定義された`FormPropsType`を`props`に設定（`props: FormPropsType`）。
ステート関数`setCity`の型は`React.Dispatch<React.SetStateAction`というもので、`useState`の内部で行われる操作系型らしい。。。
:::

#### propsに渡された関数（ここでは`props.getInfo`）

- JavaScript

（propsを渡してる側のコンポーネント）
```js
const getWeather = (e) => {
// ...処理
}
// ...省略...
<Form setCity={setCity} getInfo={getInfo} />
```
（propsを渡されてる側のコンポーネント）
```js
const Form = (props) => {
    return (
        <form onSubmit={props.getInfo}>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Get Info</button>
        </form>

    );
};
```
- TypeScript

（propsを渡してる側のコンポーネント）
```ts
const getWeather = (e: React.FormEvent<HTMLFormElement>) => {
// ...処理
}
// ...省略...
<Form setCity={setCity} getInfo={getInfo} />
```
```ts
type FormPropsType = {
    city: string;
    setCity: React.Dispatch<React.SetStateAction<string>>;
    getInfo: (e: React.FormEvent<HTMLFormElement>) => void;
}

const Form = (props: FormPropsType) => {
    return (
        <form onSubmit={props.getInfo}>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Get Info</button>
        </form>
    );
};
```

:::note
`e`が無ければ`getInfo: => void;`で良い（void型）。しかしフォームイベント`e`があるから`getInfo: (e: React.FormEvent<HTMLFormElement>) => void;`となる。
:::


#### propsに渡されたjsonデータ（ここでは`props.countriesJson`）

（propsを渡してる側のコンポーネント）
```js
<TopPage countriesJson={countriesJson} setCountry={setCountry} />
```

- JavaScript
```JS
const TopPage = (props) => {
    return (
        <div>
            <Selector countriesJson={props.countriesJson} setCountry={props.setCountry}
        </div>
    );
};
```

- TypeScript
```ts
type TopPageType = {
    countriesJson:{
        Country: string,
        Slug: string,
    }[],
    setCountry: React.Dispatch<React.SetStateAction<string>>,
}


const TopPage = (props: TopPageType) => {
    return (
        <div>
            <Selector countriesJson={props.countriesJson} setCountry={props.setCountry}
        </div>
    );
};
```

:::note
ここではJSONデータの要素（Country, Slug）が共にstring型。また、JSONでは複数の{}が[]に挟まれている形式であるがゆえに`[],`を追加する必要がある。`React.Dispatch<React.SetStateAction<string>>`は前述（propsに渡されたステート関数）
:::

<br />


#### 備考：型定義をひとつのファイルにまとめる

大規模開発ではひとつのファイルにまとめてしまう事があるらしい。

- 手順
１．場所はどこでも良いがtypes.tsファイル（名前は任意）を新規作成する。
２．各コンポーネントで定義した型定義コードをtypes.tsに移す（カット＆ペースト）。
３．types.tsにペーストしてきた型定義コードは必ず`export`させる。
例：↓
```ts
export type CountryDataType = {
    date: string,
    newConfirmed: number,
    totalConfirmed: number,
    newRecovered: number,
    totalRecovered: number,
}
```
４．カットされた各コンポーネントでは、使用していた型定義をtypes.tsからインポートする。
例：↓
```ts
import { CountryDataType, AllCountriesDataTypeArray } from "./type"
```

<br />

◆参考：[はじめてさわるReact & JavaScript with TypeScript Kindle版 三好アキ著]


<br />

# 本の宣伝
### Gatsbyバージョン５>>>>改訂２版

**前編**の『Gatsby５前編ー最新Gatsbyでつくるコーポレートサイト』と**後編**の『Gatsby５後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》』を合わせ、次のようなデモサイトを構築します。
→ **https://yah-space.work**
<hr />


静的サイトジェネレーターGatsby**最新バージョン５**の基本とFile System Route APIを使用して動的にページを生成する方法を解説。またバージョン５の新機能《**Slicy API**》《**Script API**》《**Head API**》を紹介、実装方法も。《**Gatsby Functions**》での問い合わせフォーム実装やGatsby Cloudへのアップロード方法も！


<a href="https://www.amazon.co.jp/gp/product/B0BXNJTJMY?&linkCode=li3&tag=kokkahasan-22&linkId=93c5e3bf1f226141ddc807300e81b07a&language=ja_JP&ref_=as_li_ss_il" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B0BXNJTJMY&Format=_SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=kokkahasan-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=kokkahasan-22&language=ja_JP&l=li3&o=9&a=B0BXNJTJMY" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<a target="_blank" href="https://www.amazon.co.jp/gp/product/B0BXXBDJDJ?&linkCode=ll1&tag=kokkahasan-22&linkId=df7e600968c58c0090cd735681c6732c&language=ja_JP&ref_=as_li_ss_tl">Gatsby５前編ー最新Gatsbyでつくるコーポレートサイト ～基礎の基礎から応用、新機能の導入まで（書籍2,980円）</a>

<br />
<br />

**最新Gatsby５**とmicroCMSを組み合わせてのコーポレートサイト作成手順を解説。《**サイト内検索機能**》をGatsbyバージョン４からの新機能《**Gatsby Functions**》と《**microCMSのqパラメータ**》で実装。また、**SEOコンポーネントをカスタマイズ**して**microCMS APIをツイッターカードに表示**させる**OGPタグ**実装方法も解説。

<a href="https://www.amazon.co.jp/gp/product/B0BXN99WSV?&linkCode=li3&tag=kokkahasan-22&linkId=68f1905bf915f6bd365559a0c65bcdd1&language=ja_JP&ref_=as_li_ss_il" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B0BXN99WSV&Format=_SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=kokkahasan-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=kokkahasan-22&language=ja_JP&l=li3&o=9&a=B0BXN99WSV" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<a target="_blank" href="https://www.amazon.co.jp/dp/B0BXN99WSV?_encoding=UTF8&qid=&sr=&linkCode=li2&tag=kokkahasan-22&linkId=f02e2f9c50736e3f074b38b4cd73894a&language=ja_JP&ref_=as_li_ss_il">Gatsby５後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》（書籍 2,790円）</a>






<br /><br />