# React勉強会_vol.5
###### tags:`勉強会中のメモ`
## TS基礎
* 遊び場: https://www.typescriptlang.org/play
* 型を省略しても動く→**型推論**
* 型アノテーションを省略しても自動的に補完して解釈してくれる
### 配列/オブジェクトの型定義
* 配列は以下が推奨
```javascript=
const numArr: number[] = [1, 2, 3];
```
* 狭義のオブジェクトの型指定はインターフェースを使う
```javascript=
interface Color {
readonly rgb: string;
opacity: number;
name?: string; //プロパティ名の末尾に ? をつけると、そのプロパティは省略可能
}
const turquoise: Color = { rgb: '00afcc', opacity: 1 };
```
* 任意のキーのプロパティ値を定義可能。インデックスシグネチャ
### Enumとリテラル
* リテラル
* 「~リテラル」とは別。TypeScript用語!
```javascript=
let Tom: 'Cat' = 'Cat'; // 'Cat'以外の文字列の代入を許さない
Tom = 'Dog'; // エラー!
// Enumぽいリテラルの使い方
let Mary: 'Cat' | 'Dog' | 'Rabbit' = 'Cat';
Mary = 'Rabbit'; // これはOK
Mary = 'Parrot'; // エラー!
```
* Enumよりリテラルのほうがシンプルなので好まれる
### タプル
* 個々の要素の型と、その順番や要素数に制約を設けられる特殊な配列
* 関数の引数とかで使われる概念
```javascript=
// 掲載例
const userAttrs: [number, string, boolean] = [1, 'patty', true];
const [id, username, isAdmin] = userAttrs;
console.log(id); // 1
// ちょっといじってみる
const [username, id, isAdmin] = userAttrs;
console.log(id); // "party"
```
### Any, Unknown, Never
* Unkown: 後ほど出てくる型ガードとあわせて使える
* Never: case 文の漏れを未然にチェックできるなど
## 関数とクラスの型
### 関数
* コンパイラオプションに noImplicitAny が true に指定されてないと、引数の型定義がなくても暗黙の内に any 型があてがわれてコンパイルが通ってしまう
* 引数と戻り値を別々に定義するパターン
```
const add = (n: 【引数の型】, m: 【引数の型】): 【戻り値の型】 => n + m;
戻り値がなにも返さないときはvoid
const hello = (): void => {
console.log('Hello!');
};
```
* インターフェースで一括で定義するパターン
* Reactでコンポーネントを関数で定義するときは引数と戻り値の型をそれ ぞれ定義するのではなく、React.FunctionComponentとして提供されている関数の型を適用することが多い
```javascript=
interface NumOp {
(n: number, m: number): number;
}
```
### ジェネリクス
* ジェネリックプログラミング: データの型に束縛されないよう型を抽象化してコードの再利用性を向上させつつ、静的型付け言語の持つ型安全性を維持するプログラミング手法
* ジェネリクス: 型引数を用いて表現するデータ構造
* 型引数の名前に大文字1文字を使うのは、まあ他の言語でも共通してる慣例
* なんかTSPlaygrondでジェネリクス使えない。。
### クラス
#### 継承 vs. 合成
```javascript=
class Rectangle {
readonly name = 'rectangle';
sideA: number;
sideB: number;
constructor(sideA: number, sideB: number) {
this.sideA = sideA;
this.sideB = sideB;
}
getArea = (): number => this.sideA * this.sideB;
}
```
* 継承
* 親の変更の影響を受けやすい!
```javascript=
class Square extends Rectangle {
readonly name = 'square';
// 子クラスではこれだけが公開メンバ変数。
// だが親を継承してるので、sideAとsideBも公開メンバ変数になってしまってる
side: number;
constructor(side: number) {
super(side, side);
}
// 記述はないが、getAreaメソッドは親のものを共有
// 親の変更の影響を受けやすい!
}
```
* 合成
* こちらのほうが保守性高い(とのこと。。)
```javascript=
class Square {
readonly name = 'square';
side: number;
constructor(side: number) {
this.side = side;
}
getArea = (): number => new Rectangle(this.side, this.side).getArea();
}
```
* 最近だと継承は避ける傾向にあるらしい
* 継承よりも合成
### 抽象クラス vs. インターフェース
* 抽象クラスは定義に実装を含むことができてしまう
* ↑の議論からするに、避けるべきは実装を伴った継承
* インターフェース: 実装を伴わずに型だけを適用できる
* Javaのインターフェース(継承先に実装するべきメンバ変数とメソッドを定義するもの)と混同しないこと!
* クラスは TypeScript にとって、型でもあり関数でもある
## 型の名前と型合成
* 型エイリアス: 任意の型に別名を与えて再利用できる
### インターフェースとの違い
* インターフェース文
* 型の宣言
* 関数でいうと「関数宣言」
* 型エイリアス
* すでに作られた型の参照に別名をつけている
* 関数でいうと「関数式」
* 今となっては型エイリアスのほうが表現力が高い→インターフェースよりも型エイリアスを使う!
###