【TypeScript】クラス、インターフェースについて

# 概要
TypeScriptでクラスについて学んだことをまとめる。

# 基本的構造
コードを例に説明する。


````
// classの宣言
class Position {
  // コンストラクターはインスタンス生成時に実行
  // private演算子でインスタンス内部でしかアクセスできないように指定
  constructor(private readonly latitude: number, private readonly longitude: number) {}

  // メソッド
  public getPosition() {
    return {
      'latitude': this.latitude,
      'longitude': this.longitude
    }
}

// インスタンス生成
let position = new Position(23.33, 134.23);
// メソッドの呼び出し
positon.getPosition();
```

class宣言は、`class クラス名`により定義することができる。
そしてインスタンス生成は、`new`演算子を使用する。

# アクセス演算子
クラスとのアクセス演算子には大きく分けて以下の３つがある。

- public
どこからでもアクセス可能

- protected
このクラスとサブクラスのインスタンスからからアクセス可能

- private
このクラスのインスタンスからのみアクセス可能

モジュールの結合度を上げる観点から、なるべく`private`演算子を使用し、`public`を最小限に止める設計にすること。


# super
　子クラスがオーバライドした際に、親クラスのオーバーライドされたメソッドを呼び出すときに使用する。
　ただし、呼び出せるのはメソッドだけであり、プロパティ呼び出すことは不可。
コンストラタとメソッドで少し書き方が違うため注意すること。

```
class City extends Position{
  private latitude = '';
  private longitude = '';

  constructor(latitude: number, longitude: number) {
    // 親のクラスのコンストラクタを呼び出す
    // thisを使用する前に呼び出す必要あり（コンストラクトの一行目に書けば良い）
    super(latitude, longitude);        
    this.latitude = latitude;
    this.longitude = longitude;
  }
  // オーバーライド
  getPosition() {
    return {
      'latitude': Math.trunc(this.latitude),
      'longitude': Math.trunc(this.longitude)
    }
  }
  // Cityクラス（子クラス）のメソッドが呼ばれる
  this.getPostion();
  // Positionクラス（親クラス）のメソッドが呼ばれる
  super.getPositoin();
}
```

# this
　`this`はそのクラス自身のインスタンス型を示す。
thisを記述すると良い例を以下に示す。

```
class Set {
  add(value: number): this {
    // 返り値の型はthisに設定
  }
}

class MutableSet extends Set {
  // addメソッドはオーバーライドでは記述しない
}

let set = new Set();
let mutableSet = new MutableSet();

set.add(2);           // 返り値はSetのインスタンス型
mutableSet.add(3);    // MutableSetのインスタンス型
```

# インターフェース
　型を定義するものである。使用方法は以下の通り。


```
// インターフェースの定義
interface User {
  userId: string
  userName: string
  getUserName(userId: string, user: string[]): string
}

// クラスに実装
class Customer implements User {
  getUserName(private userId: string, private userName) {
    return this.userId + ':' + this.userName;
  }
}    
```

# クラスは値と型を持つ
　クラスを宣言すると、型も宣言することなる。つまり、クラス宣言するとインターフェース宣言したことにもなる。


```
class Position {
  constructor(private readonly latitude: number, private readonly longitude: number) {}

  public getLatitude() {
    return this.latitude;
}

// 型としてPositionをアノテーションできる
let position: Position = new Position(123, 23);

/*
上記のクラスを定義すると以下のインターフェースを定義される
interface Position {
  getPosition(): number
}
*/
```

# ジェネリック型パラメーター
　インスタンス生成する際に渡すパラメータの型が、インスタンス生成するまでわからない場合ジェネリック型パラメータを使用する。

```
class Position<T, K> {
  constructor(private readonly latitude: T, private readonly longitude: K) {}

  public getLatitude(): K {
    return this.latitude;
}

// T: number, K: number
let position = new Position(123, 23);
// 返り値はnumber
position.getLatitude();

// T: string, K: string
let position = new Position('123', '23');
// 返り値はstring
position.getLatitude();

```

# 継承、インスタンス化を禁止

```
class Position<T, K> {
  // constructorにprivate演算子をつけることでインスタンス化、継承をするとエラーになる
  private constructor(private readonly latitude: T, private readonly longitude: K) {}
}
```

# 最後に
　クラス、インターフェースについてまとめてみました。
間違っている箇所あればコメントお願いします。

# 参考
boris cherny 著　「ぷおぐらミングTypeScritpt」　オライリー・ジャパン