---
# System prepended metadata

title: React勉強会_vol.5
tags: [勉強会中のメモ]

---

# 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 にとって、型でもあり関数でもある

## 型の名前と型合成

* 型エイリアス: 任意の型に別名を与えて再利用できる

### インターフェースとの違い

* インターフェース文
    * 型の宣言
    * 関数でいうと「関数宣言」
* 型エイリアス
    * すでに作られた型の参照に別名をつけている
    * 関数でいうと「関数式」
* 今となっては型エイリアスのほうが表現力が高い→インターフェースよりも型エイリアスを使う!

### 