React × TypeScript 型の指定方法

# プリミティブ型
```react
// boolean型 真偽値
let bool: boolean = true;

// number型 数値
let num: number = 0;

// strintg型 文字
let str: string = "hoge";

// Array型 配列
let arr2: number[] = [0, 1, 2];
let arr1: Array<number> = [0, 1, 2];

// Array型 二次元配列
let nijigenHariretsu: number[][] = [
  [50, 100],
  [150, 300],
];

// tuple型 複数の値を保持することができる型
let tuple: [number, string, string] = [0, "foo", "bar"]

// any型 どんな型でも代入することができる型
let any: any = false; // OK

// unknown

// object型 オブジェクト
let profile: { name: string, age: number } = { name: "hoge", age: 20 }

// void型 何もデータが存在しない状態を表す型
function returnNothing(): void {
  console.log('return anything!');
}

// never型 例外処理など、値の返却がない場合に使用する型
function error(message: string): never {
  throw new Error(message);
}

// null型 用いることのできる値がないことを示す状態を表す型
let absence: null = null;

// undefined型　何も設定されていない状態を表す型
let undef: undefined = undefined;
```

※ 配列について、二通りの指定方法がありますが`Array<xxx>`は非推奨とされています。

# 引数

```react
// 数値の場合
const count = (num: number) => {

// 文字列の場合
const user = (name: string) => {
```

初期値を設定する場合

```react
const count = (num: number = 10) => {
```

引数がない場合、初期値として`num`に`10` が代入されます。

# 返却値
`return`で返却される値に型を指定

```react
const getTotalFee = (num: number): number => {
  const total = num * 1.08;
  return total;
};
```

# 変数

```react
let total: number = 0;
```

# オプショナルチェイニング
プロパティーの末尾に`?`を付けることで省略可能にしています。
逆に付けなければ、そのプロパティーは**必須**となり、指定しないとエラーになります。

```typescript
profile?: string;
```

# 型エイリアスの定義

- オブジェクトや配列の型を強制して取得データを定義することができます。
 - ここでは、配列でオブジェクトを取得する想定で定義しており、`useState`や`props`、`axios`の`get`メソッドで使用しています。

```typescript
import { useState } from "react";

type UserType = {
  id: number;
  name: string;
  email: string;
  password: string;
};

export const User = () => {
  const [users, setUsers] = useState<Array<UserType>>([]);

  const onClickUserData = (props: UserType) => {
    axios
      .get<Array<UserType>>("http://localhost:3000/api/v1")
      .then((res) => {
        setUsers(res.data);
      });
  };
```

**ハッシュ値を定義する場合**

```typescript
type UserType = {
  user?: { id: number, name: string, email: string, password: string };
  id: number;
  name: string;
  email: string;
  password: string;
};
```

# 型エイリアスの管理方法
他コンポートネントでも使えるように`src`直下に`types`ディレクトリを作成し、その中で型エイリアスを定義することで効率的に管理することができます。

```typescript:src/types/user.ts
export type UserType = {
  id: number;
  name: string;
  email: string;
  password: string;
};
```
他コンポーネントで使用できるように`export`を先頭に付けています。

```typescript:src/User.tsx
import { useState } from "react";
import { UserType } from "../types/user";

export const User = () => {
  const [users, setUsers] = useState<Array<UserType>>([]);
```
`import`するだけで使用できるようになります。

# 型エイリアスの継承(仮)

`交差型(&)`を使用することで、継承と似たことを実現させています。

```react:src/types/user.ts
export type UserType = {
  id: number;
  name: string;
  email: string;
  password: string;
};

export type UserProfileType = Omit<UserType, 'password'> & {
  profile: string;
  image: string;
};
```

`Omit`で必要のない`password`を取り除き、新たに必要となる`profile`と`image`を追加してユーザープロフィール専用の型を定義しています。

# 関数コンポーネントの型定義
関数コンポーネントを定義するための型で、関数名の末尾に`: FC<型エイリアス>`とすることで使用できます。

```typescript
import { FC } from "react";
import { UserType } from "../types/user";

export const User: FC<UserType> = ({id, name, email, password}) => {
  ...
```
`UserType`に定義しているプロパティ名を引数として`{}`で囲って`props`を使用しています。

```typescript
// 型エイリアスを使用しない場合
import { FC } from "react";

export const User: FC<{ id: number, name: string, email: string, password: string }> = ({
  id, name, email, password
}) => {
  ...
```

## `Pick` or `Omit`
既存の型から利用したいプロパティーのみを抽出して型定義することができます。

```typescript
type UserType = {
  id: number;
  name: string;
  email: string;
  password: string;
};
type UserProfileType = Pick<UserType, "id" | "name" | "email">;

export const UserProfile<UserProfileType> = (props) => {
  const {id, name, email} = props;
```
`Pick`を使用することで型の中から必要なプロパティーのみ指定して定義することができます。

```typescript
type UserType = {
  id: number;
  name: string;
  email: string;
  password: string;
};
type UserProfileType = Omit<UserType, "password">;

export const UserProfile<UserProfileType> = (props) => {
  const {id, name, email} = props;
```
`Omit`は`Pick`の逆で指定したプロパティーを除いて型を定義することができます。

## 参考教材

https://www.udemy.com/course/react_stepup/

https://www.udemy.com/course/ts-for-js-developers/