ReactにTypeScriptを導入【Tips集】

ReactにTypeScriptを導入したときのTipsをまとめました。
一助となればこれ幸い。
※基礎編レベルになります

## 手始め

### App.tsxで書いてみる

ファイル`App.js`を`App.tsx`に変更

```javascript:App.tsx
import React, { FC } from 'react';

const App: FC = ()  => {
  const sum = (a: number, b: number): number => {
    return a + b;
  };
  return (
    <>
      <p>{sum(1, 2)}</p>
    </>
  );
};

export default App;
```
- `FC`はFunctional Component型の指定

## Tips

### interface

```typescript
interface Todo {
  text: string;
  complete: boolean;
  name?: string;
  readonly x: number;
}
```

- 型の定義をまとめる
- 関数やオブジェクト、配列をまとめることができる
- interfaceの名前の頭文字は大文字
- name?は任意のプロパティ
- `readonly`は読み込み専用、xを変更することができない

```typescript
let hoge: Hoge = { x: 10 };
hoge.x = 5; // error
```

参考サイト

- [Typescriptのinterfaceの使い方](https://qiita.com/nogson/items/86b47ee6947f505f6a7b)

### 継承

```typescript
interface Todo {
  text: string;
  complete: boolean;
}

interface Todo2 extend Todo {
  tags: string[];
}
```

- `extend`で型を継承
- `string[]`は配列型で配列の中身がstring

### 外部ファイルで管理

```typescript

export interface Action {
  type: string;
  payload: Hoge[];
}
```

- exportで外部ファイルに適用
- 複数interfaceを1つのファイルで管理可能

### 分割代入に適用

```typescript
const { hoge }: { hoge: Data[] } = state;
```

- `: { hoge: Data[] }`で変数hogeの型指定
- `Data[]`は配列型で配列の中身がinterfaceの`Data`


### useState

#### パターン1 

```typescript
const [value, setValue] = useState<string>('');
```

- useStateに文字列型を指定

#### パターン2

```typescript
interface Todo {
  text: string;
  complete: boolean;
}

const [todos, setTodos] = useState<Todo[]>([]);
```

- useStateにオブジェクト型を指定
- `Todo[]`は配列型で配列の中身がinterfaceのTodo

#### パターン3

```typescript
interface State {
  notificationVisible: boolean;
}

const [state, setState] = useState<State>({
  notificationVisible: true
});

const handleClick = () => {
  setState({
    notificationVisible: false
  });
```

- Genericsで型指定したときの書き方


### propsの型指定

```typescript
interface HogeProps {
  name: string;
  age: number;
  prefecture?: string;
}

const Hoge: FC<HogeProps> = ({ name, age }) => {
```

### 関数に適用

```typescript
interface Todo {
  text: string;
  complete: boolean;
}

const addTodo = (text: string): void => {
  const newTodos: Todo[] = [...todos, { text, complete: false }];
  setTodos(newTodos);
};
```

- `: void`はreturn(返り値)がないときに指定


### formのonSubmitのEventの型指定

```typescript
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();
};

<form onSubmit={handleSubmit}>
```

- formの`onSubmit`関数の引数に`React.FormEvent`を指定

### formのonChangeのEventの型指定

```typescript
const [hoge, setHoge] = useState('');

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const { value }: { value: string } = e.target;
  setHoge(value);
};

<input type="text" value={hoge} onChange={handleChange} />
```

- onChangeのevent関数の引数に`React.ChangeEvent<HTMLInputElement>)`を指定
- `const { value }: { value: string }`は分割代入の型指定

### mapで展開するときの型指定

```typescript
interface Todo {
  text: string;
  complete: boolean;
}

<ul>
  {
    todos.map((todo: Todo, index: number) => (
      <li key={index}>{todo.text}</li>
    ))
  }
</ul>
```

### stateとactionに導入

```typescript
import React, { createContext } from 'react';

const FETCH_DATA: string = 'FETCH_DATA';

interface State {
  hoge: [];
}

interface Hoge {
  name: string;
  age: number;
}

interface Action {
  type: string;
  payload: Hoge[];
}

const initialState:State = {
  hoge: [];
};

const Index = createContext<State>(initialState);

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case FETCH_DATA:
      return { ...state, hoge: action.payload };
    default:
      return state;
  }
};
```

### lazyに適用

```typescript
import React, { lazy } from 'react';

const Hoge = lazy<any>(() => import('./Hoge'));
```

### dispatchに適用

```typescript
interface Hoge {
  name: string;
  age: number;
}

interface Action {
  type: string;
  payload: Hoge[];
}

type Dispatch = React.Dispatch<Action>

interface Foo {
  store: { state: State, dispatch: Dispatch }
}
```

- storeの型を指定
- `Hoge[]`は配列型で配列の中身がinterfaceのHoge